Skip to content

Commit c8be9ab

Browse files
committed
BrandingUpload component, return spinner while loading; SubBranding schema validation
1 parent 45f9926 commit c8be9ab

File tree

2 files changed

+50
-19
lines changed

2 files changed

+50
-19
lines changed

components/territory-branding.js

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,30 @@ import { useToast } from '@/components/toast'
22
import { SUB_BRANDING, UPSERT_SUB_BRANDING } from '@/fragments/subs'
33
import { useMutation, useQuery } from '@apollo/client'
44
import { subBrandingSchema } from '@/lib/validate'
5-
import { Form, Input, ColorPicker, SubmitButton } from '@/components/form'
5+
import { Form, Input, ColorPicker, SubmitButton, BrandingUpload } from '@/components/form'
66
import AccordianItem from '@/components/accordian-item'
7+
import Moon from '@/svgs/moon-fill.svg'
78

89
export default function TerritoryBrandingForm ({ sub }) {
910
const [upsertSubBranding] = useMutation(UPSERT_SUB_BRANDING)
1011
const toaster = useToast()
1112

12-
const { data } = useQuery(SUB_BRANDING, {
13+
const { data, loading } = useQuery(SUB_BRANDING, {
1314
variables: { subName: sub.name }
1415
})
1516

16-
const subBranding = data?.sub?.branding
17+
if (loading) {
18+
return <Moon className='spin fill-grey' style={{ width: '1rem', height: '1rem' }} />
19+
}
20+
21+
const subBranding = data?.subBranding || {
22+
title: sub.name,
23+
description: sub.desc,
24+
primaryColor: '#FADA5E',
25+
secondaryColor: '#F6911D',
26+
logoId: null,
27+
faviconId: null
28+
}
1729

1830
const onSubmit = async (values) => {
1931
try {
@@ -23,27 +35,27 @@ export default function TerritoryBrandingForm ({ sub }) {
2335
branding: {
2436
title: values.title,
2537
description: values.description,
26-
primaryColor: values.primary,
27-
secondaryColor: values.secondary,
38+
primaryColor: values.primaryColor,
39+
secondaryColor: values.secondaryColor,
2840
logoId: values.logoId,
2941
faviconId: values.faviconId
3042
}
3143
}
3244
})
33-
toaster.success('Branding updated successfully')
45+
toaster.success('branding updated successfully')
3446
} catch (error) {
3547
console.error(error)
36-
toaster.danger('Failed to update branding', { error })
48+
toaster.danger('failed to update branding', { error })
3749
}
3850
}
3951

4052
const initialValues = {
41-
title: subBranding?.title || sub?.name,
42-
description: subBranding?.description || '',
43-
primaryColor: subBranding?.primaryColor || '#FADA5E',
44-
secondaryColor: subBranding?.secondaryColor || '#F6911D',
45-
logoId: subBranding?.logoId || null,
46-
faviconId: subBranding?.faviconId || null
53+
title: subBranding.title,
54+
description: subBranding.description,
55+
primaryColor: subBranding.primaryColor,
56+
secondaryColor: subBranding.secondaryColor,
57+
logoId: subBranding.logoId,
58+
faviconId: subBranding.faviconId
4759
}
4860

4961
return (
@@ -55,8 +67,8 @@ export default function TerritoryBrandingForm ({ sub }) {
5567
<Input label='title' name='title' />
5668
<Input label='description' name='description' />
5769
<div className='row'>
58-
<ColorPicker groupClassName='col-4' label='primary color' name='primary' />
59-
<ColorPicker groupClassName='col-4' label='secondary color' name='secondary' />
70+
<ColorPicker groupClassName='col-4' label='primary color' name='primaryColor' />
71+
<ColorPicker groupClassName='col-4' label='secondary color' name='secondaryColor' />
6072
</div>
6173
<AccordianItem
6274
header={<div className='fw-bold text-muted'>logo and favicon</div>}
@@ -65,15 +77,13 @@ export default function TerritoryBrandingForm ({ sub }) {
6577
<div className='col-2'>
6678
<label className='form-label'>logo</label>
6779
<div style={{ position: 'relative', width: '100px', height: '100px', border: '1px solid #dee2e6', borderRadius: '5px', overflow: 'hidden' }}>
68-
<p>placeholder</p>
69-
{/* <BrandingUpload name='logoId' /> */}
80+
<BrandingUpload name='logoId' />
7081
</div>
7182
</div>
7283
<div className='col-2'>
7384
<label className='form-label'>favicon</label>
7485
<div style={{ position: 'relative', width: '100px', height: '100px', border: '1px solid #dee2e6', borderRadius: '5px', overflow: 'hidden' }}>
75-
<p>placeholder</p>
76-
{/* <BrandingUpload name='faviconId' /> */}
86+
<BrandingUpload name='faviconId' />
7787
</div>
7888
</div>
7989
</div>

lib/validate.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,27 @@ export function customDomainSchema (args) {
365365
})
366366
}
367367

368+
// Sub Branding validation schema
369+
// sanitize the input for correct colors and text
370+
export function subBrandingSchema (args) {
371+
return object({
372+
title: string().max(100, 'must be at most 100 characters').matches(/^[a-zA-Z0-9\s]+$/, {
373+
message: 'title must only contain letters, numbers, and spaces'
374+
}).nullable().trim(),
375+
description: string().max(250, 'must be at most 250 characters').matches(/^[a-zA-Z0-9\s]+$/, {
376+
message: 'description must only contain letters, numbers, and spaces'
377+
}).nullable().trim(),
378+
logoId: intValidator.nullable().positive('must be positive').integer('must be an integer'),
379+
faviconId: intValidator.nullable().positive('must be positive').integer('must be an integer'),
380+
primaryColor: string().matches(/^#([0-9a-fA-F]{6})$/, {
381+
message: 'primary color must be a valid hex color'
382+
}).nullable(),
383+
secondaryColor: string().matches(/^#([0-9a-fA-F]{6})$/, {
384+
message: 'secondary color must be a valid hex color'
385+
}).nullable()
386+
})
387+
}
388+
368389
export function userSchema (args) {
369390
return object({
370391
name: nameValidator

0 commit comments

Comments
 (0)