/
UserReviewSubmit.tsx
113 lines (102 loc) · 2.91 KB
/
UserReviewSubmit.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { Paper, Rating, Stack, Textarea, useMantineTheme } from '@mantine/core'
import { useForm, zodResolver } from '@mantine/form'
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
import { useEffect } from 'react'
import { z } from 'zod'
import { type ApiInput } from '@weareinreach/api'
import { trpc as api } from '~ui/lib/trpcClient'
import { Button } from './Button'
import { UserAvatar } from './UserAvatar'
const RouterSchema = z.object({
slug: z.string(),
orgLocationId: z.string().optional(),
serviceId: z.string().optional(),
})
const ReviewSchema = z.object({
organizationId: z.string(),
orgLocationId: z.string().optional(),
orgServiceId: z.string().optional(),
rating: z.number(),
reviewText: z.string().optional(),
})
export const UserReviewSubmit = ({ type = 'body', closeModalHandler }: ReviewSubmitProps) => {
const { t } = useTranslation()
const theme = useMantineTheme()
const { query: rawQuery } = useRouter()
const query = RouterSchema.parse(rawQuery)
const { data: orgQuery, status } = api.organization.getIdFromSlug.useQuery(query, { enabled: !!query })
const { orgLocationId, serviceId } = query
const apiUtil = api.useUtils()
const submitReview = api.review.create.useMutation({
onSuccess: () => {
apiUtil.organization.forOrgPage.invalidate()
apiUtil.location.forLocationPage.invalidate()
if (closeModalHandler instanceof Function) {
closeModalHandler()
}
},
})
const form = useForm<FormFields>({
initialValues: {
orgLocationId,
organizationId: orgQuery?.id ?? '',
orgServiceId: serviceId,
rating: 0,
},
validate: zodResolver(ReviewSchema),
})
useEffect(() => {
if (status === 'success' && orgQuery?.id) {
form.setFieldValue('organizationId', orgQuery.id)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [status, orgQuery?.id])
const isBody = type === 'body'
const component = (
<form
onSubmit={form.onSubmit((values) => {
submitReview.mutate(values)
})}
>
<Stack align='flex-start' spacing='xl'>
<UserAvatar useLoggedIn={true} avatarSize={48} />
<Rating {...form.getInputProps('rating')} />
<Textarea
label={t('review-resource')}
placeholder={t('enter-review') satisfies string}
description={t('review-note')}
{...form.getInputProps('reviewText')}
/>
<Button variant={isBody ? 'primary' : 'primary-icon'} fullWidth={!isBody} type='submit'>
{t('submit-review')}
</Button>
</Stack>
</form>
)
switch (type) {
case 'modal': {
return component
}
case 'body': {
return (
<Paper withBorder radius='lg' p={theme.spacing.lg}>
{component}
</Paper>
)
}
default: {
return null
}
}
}
type FormFields = ApiInput['review']['create']
type ReviewSubmitProps = {
/**
* Is this being used in a page body or in a modal?
*
* Page body will add a Grid.Col wrapper
*/
type?: 'body' | 'modal'
closeModalHandler?: () => void
}