add role checkbox
This commit is contained in:
parent
c8282e8c04
commit
7a3ad37bf3
@ -1,14 +1,10 @@
|
||||
'use server';
|
||||
import { authOptions } from '@/config/auth';
|
||||
import { getCustomer, updateCustomerProfile } from '@repo/graphql/api';
|
||||
import { type CustomerInput } from '@repo/graphql/types';
|
||||
import { type CustomerInput, type Enum_Customer_Role } from '@repo/graphql/types';
|
||||
import { getServerSession } from 'next-auth/next';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function becomeMaster() {
|
||||
revalidatePath('/profile');
|
||||
}
|
||||
|
||||
export async function updateProfile(input: CustomerInput) {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
@ -26,3 +22,23 @@ export async function updateProfile(input: CustomerInput) {
|
||||
|
||||
revalidatePath('/profile');
|
||||
}
|
||||
|
||||
export async function updateRole(role: Enum_Customer_Role) {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (session) {
|
||||
const { user } = session;
|
||||
const getCustomerResponse = await getCustomer({ telegramId: user?.telegramId });
|
||||
const customer = getCustomerResponse.data.customers.at(0);
|
||||
if (customer) {
|
||||
await updateCustomerProfile({
|
||||
data: {
|
||||
role,
|
||||
},
|
||||
documentId: customer.documentId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
revalidatePath('/profile');
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { becomeMaster, updateProfile } from '@/actions/profile';
|
||||
import { updateProfile, updateRole } from '@/actions/profile';
|
||||
import { CheckboxWithText } from '@/components/profile/checkbox-with-text';
|
||||
import { ProfileField } from '@/components/profile/profile-field';
|
||||
import { authOptions } from '@/config/auth';
|
||||
import { getCustomer } from '@repo/graphql/api';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@repo/ui/components/ui/avatar';
|
||||
import { Button } from '@repo/ui/components/ui/button';
|
||||
import { Card, CardContent, CardHeader } from '@repo/ui/components/ui/card';
|
||||
import { getServerSession } from 'next-auth/next';
|
||||
|
||||
@ -34,23 +34,12 @@ export default async function ProfilePage() {
|
||||
value={user?.name ?? ''}
|
||||
/>
|
||||
<ProfileField disabled id="phone" label="Телефон" value={user?.phone ?? ''} />
|
||||
<ProfileField
|
||||
disabled
|
||||
id="status"
|
||||
label="Статус"
|
||||
value={user?.role === 'client' ? 'Клиент' : 'Мастер'}
|
||||
<CheckboxWithText
|
||||
checked={user.role !== 'client'}
|
||||
description="Разрешить другим пользователям записываться к вам"
|
||||
onChange={updateRole}
|
||||
text="Быть мастером"
|
||||
/>
|
||||
{user?.role === 'client' && (
|
||||
<form action={becomeMaster}>
|
||||
<Button
|
||||
className="w-full bg-gradient-to-r from-purple-500 to-purple-700 text-white hover:from-purple-600 hover:to-purple-800
|
||||
dark:from-purple-700 dark:to-purple-900 dark:hover:from-purple-800 dark:hover:to-purple-950"
|
||||
type="submit"
|
||||
>
|
||||
Стать мастером
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
63
apps/web/components/profile/checkbox-with-text.tsx
Normal file
63
apps/web/components/profile/checkbox-with-text.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
/* eslint-disable canonical/id-match */
|
||||
/* eslint-disable promise/prefer-await-to-then */
|
||||
'use client';
|
||||
import { Enum_Customer_Role } from '@repo/graphql/types';
|
||||
import { Checkbox, type CheckboxProps } from '@repo/ui/components/ui/checkbox';
|
||||
import { useState } from 'react';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
type Props = Pick<CheckboxProps, 'checked'> & {
|
||||
readonly description?: string;
|
||||
readonly onChange?: (value: Enum_Customer_Role) => Promise<void> | void;
|
||||
readonly text: string;
|
||||
};
|
||||
|
||||
export function CheckboxWithText({ checked: initialValue, description, onChange, text }: Props) {
|
||||
const [checked, setChecked] = useState(initialValue);
|
||||
const { debouncedCallback, isPending } = useDebouncedOnChangeCallback(onChange);
|
||||
|
||||
const handleChange = () => {
|
||||
const newValue = !checked;
|
||||
setChecked(newValue);
|
||||
debouncedCallback(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-start space-x-2">
|
||||
<Checkbox checked={checked} disabled={isPending} id="terms1" onCheckedChange={handleChange} />
|
||||
<div className="grid gap-1.5 leading-none">
|
||||
<label
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
htmlFor="terms1"
|
||||
>
|
||||
{text}
|
||||
</label>
|
||||
{description ? <p className="text-sm text-muted-foreground">{description}</p> : false}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function useDebouncedOnChangeCallback(
|
||||
callback: ((value: Enum_Customer_Role) => Promise<void> | void) | undefined,
|
||||
) {
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
|
||||
const debouncedCallback = useDebouncedCallback((checked: boolean) => {
|
||||
if (!callback) return;
|
||||
|
||||
setIsPending(true);
|
||||
const result = callback(checked ? Enum_Customer_Role.Master : Enum_Customer_Role.Client);
|
||||
|
||||
if (result instanceof Promise) {
|
||||
result.finally(() => setIsPending(false));
|
||||
} else {
|
||||
setIsPending(false);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
return {
|
||||
debouncedCallback,
|
||||
isPending,
|
||||
};
|
||||
}
|
||||
@ -45,6 +45,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-avatar": "catalog:",
|
||||
"@radix-ui/react-checkbox": "^1.1.3",
|
||||
"@radix-ui/react-label": "^2.1.1",
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:"
|
||||
|
||||
29
packages/ui/src/components/ui/checkbox.tsx
Normal file
29
packages/ui/src/components/ui/checkbox.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
'use client';
|
||||
|
||||
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
||||
import { cn } from '@repo/ui/lib/utils';
|
||||
import { Check } from 'lucide-react';
|
||||
import * as React from 'react';
|
||||
|
||||
const Checkbox = React.forwardRef<
|
||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CheckboxPrimitive.Root
|
||||
className={cn(
|
||||
'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<CheckboxPrimitive.Indicator className={cn('flex items-center justify-center text-current')}>
|
||||
<Check className="size-4" />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
));
|
||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
||||
|
||||
export { Checkbox };
|
||||
|
||||
export { type CheckboxProps } from '@radix-ui/react-checkbox';
|
||||
107
pnpm-lock.yaml
generated
107
pnpm-lock.yaml
generated
@ -378,6 +378,9 @@ importers:
|
||||
'@radix-ui/react-avatar':
|
||||
specifier: 'catalog:'
|
||||
version: 1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-checkbox':
|
||||
specifier: ^1.1.3
|
||||
version: 1.1.3(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-label':
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
@ -2022,6 +2025,9 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
'@radix-ui/primitive@1.1.1':
|
||||
resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==}
|
||||
|
||||
'@radix-ui/react-avatar@1.1.2':
|
||||
resolution: {integrity: sha512-GaC7bXQZ5VgZvVvsJ5mu/AEbjYLnhhkoidOboC50Z6FFlLA03wG2ianUoH+zgDQ31/9gCF59bE4+2bBgTyMiig==}
|
||||
peerDependencies:
|
||||
@ -2035,6 +2041,19 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-checkbox@1.1.3':
|
||||
resolution: {integrity: sha512-HD7/ocp8f1B3e6OHygH0n7ZKjONkhciy1Nh0yuBgObqThc3oyx+vuMfFHKAknXRHHWVE9XvXStxJFyjUmB8PIw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-compose-refs@1.1.1':
|
||||
resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==}
|
||||
peerDependencies:
|
||||
@ -2066,6 +2085,19 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-presence@1.1.2':
|
||||
resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-primitive@2.0.1':
|
||||
resolution: {integrity: sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==}
|
||||
peerDependencies:
|
||||
@ -2097,6 +2129,15 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.1.0':
|
||||
resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.1.0':
|
||||
resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==}
|
||||
peerDependencies:
|
||||
@ -2106,6 +2147,24 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-previous@1.1.0':
|
||||
resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-size@1.1.0':
|
||||
resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@repeaterjs/repeater@3.0.4':
|
||||
resolution: {integrity: sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==}
|
||||
|
||||
@ -7977,6 +8036,8 @@ snapshots:
|
||||
dependencies:
|
||||
playwright: 1.49.1
|
||||
|
||||
'@radix-ui/primitive@1.1.1': {}
|
||||
|
||||
'@radix-ui/react-avatar@1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-context': 1.1.1(@types/react@19.0.1)(react@19.0.0)
|
||||
@ -7989,6 +8050,22 @@ snapshots:
|
||||
'@types/react': 19.0.1
|
||||
'@types/react-dom': 19.0.1
|
||||
|
||||
'@radix-ui/react-checkbox@1.1.3(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.1
|
||||
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0)
|
||||
'@radix-ui/react-context': 1.1.1(@types/react@19.0.1)(react@19.0.0)
|
||||
'@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.1)(react@19.0.0)
|
||||
'@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.1)(react@19.0.0)
|
||||
'@radix-ui/react-use-size': 1.1.0(@types/react@19.0.1)(react@19.0.0)
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.1
|
||||
'@types/react-dom': 19.0.1
|
||||
|
||||
'@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.1)(react@19.0.0)':
|
||||
dependencies:
|
||||
react: 19.0.0
|
||||
@ -8010,6 +8087,16 @@ snapshots:
|
||||
'@types/react': 19.0.1
|
||||
'@types/react-dom': 19.0.1
|
||||
|
||||
'@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0)
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.1
|
||||
'@types/react-dom': 19.0.1
|
||||
|
||||
'@radix-ui/react-primitive@2.0.1(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-slot': 1.1.1(@types/react@19.0.1)(react@19.0.0)
|
||||
@ -8032,12 +8119,32 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.1
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.1)(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.1)(react@19.0.0)
|
||||
react: 19.0.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.1
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.1)(react@19.0.0)':
|
||||
dependencies:
|
||||
react: 19.0.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.1
|
||||
|
||||
'@radix-ui/react-use-previous@1.1.0(@types/react@19.0.1)(react@19.0.0)':
|
||||
dependencies:
|
||||
react: 19.0.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.1
|
||||
|
||||
'@radix-ui/react-use-size@1.1.0(@types/react@19.0.1)(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0)
|
||||
react: 19.0.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.1
|
||||
|
||||
'@repeaterjs/repeater@3.0.4': {}
|
||||
|
||||
'@repeaterjs/repeater@3.0.6': {}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user