From 3cfad5df587a2da2880a75caa9f9a2b8f71adbe8 Mon Sep 17 00:00:00 2001 From: sdjdd Date: Mon, 22 Jan 2024 11:46:18 +0800 Subject: [PATCH] feat: update customer service nickname & email --- next/api/src/controller/customer-service.ts | 16 ++++++- next/api/src/controller/user.ts | 2 + .../components/CustomerServiceForm.tsx | 47 +++++++++++++++++++ .../src/App/Admin/Settings/Members/index.tsx | 40 +++++++++++----- .../src/App/Admin/Settings/Users/index.tsx | 14 +++++- next/web/src/api/customer-service.ts | 4 +- next/web/src/api/user.ts | 1 + 7 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 next/web/src/App/Admin/Settings/Members/components/CustomerServiceForm.tsx diff --git a/next/api/src/controller/customer-service.ts b/next/api/src/controller/customer-service.ts index 131b05201..f5aa9e7c4 100644 --- a/next/api/src/controller/customer-service.ts +++ b/next/api/src/controller/customer-service.ts @@ -35,7 +35,7 @@ class FindCustomerServicePipe { } } -const roleSchema = z.union([z.literal('admin'), z.literal('customerService')]); +const roleSchema = z.enum(['admin', 'customerService']); const rolesSchema = z.array(roleSchema).nonempty(); const createCustomerServiceSchema = z.object({ @@ -54,6 +54,8 @@ type AddCategoryData = z.infer; const updateCustomerServiceSchema = z.object({ active: z.boolean().optional(), roles: rolesSchema.optional(), + nickname: z.string().optional(), + email: z.string().optional(), }); type UpdateCustomerServiceData = z.infer; @@ -133,6 +135,18 @@ export class CustomerServiceController { processQueue.push(roleService.updateUserCSRoleTo(data.roles, user.id)); } + if (data.nickname || data.email) { + processQueue.push( + user.update( + { + name: data.nickname, + email: data.email, + }, + { useMasterKey: true } + ) + ); + } + await Promise.all(processQueue); return {}; diff --git a/next/api/src/controller/user.ts b/next/api/src/controller/user.ts index a9a9e8014..5797e8a05 100644 --- a/next/api/src/controller/user.ts +++ b/next/api/src/controller/user.ts @@ -60,6 +60,7 @@ type AuthData = z.infer; const preCraeteSchema = z.object({ email: z.string().email().optional(), username: z.string().optional(), + nickname: z.string().optional(), }); type PreCreateUserData = z.infer; @@ -204,6 +205,7 @@ export class UserController { { // username might be `""` username: username ? username : email, + name: data.nickname, email, password: Math.random().toString(), }, diff --git a/next/web/src/App/Admin/Settings/Members/components/CustomerServiceForm.tsx b/next/web/src/App/Admin/Settings/Members/components/CustomerServiceForm.tsx new file mode 100644 index 000000000..8119a22fe --- /dev/null +++ b/next/web/src/App/Admin/Settings/Members/components/CustomerServiceForm.tsx @@ -0,0 +1,47 @@ +import { forwardRef } from 'react'; +import { Form, FormInstance, Input } from 'antd'; + +import { CSRole } from '@/api/customer-service'; +import { RoleCheckboxGroup } from '@/App/Admin/components/RoleCheckboxGroup'; + +export interface CustomerServiceFormData { + nickname?: string; + email?: string; + roles?: CSRole[]; +} + +export interface CustomerServiceFormProps { + initData?: Partial; + onSubmit?: (data: CustomerServiceFormData) => void; +} + +export const CustomerServiceForm = forwardRef( + ({ initData, onSubmit }, ref) => { + const handleSubmit = (data: CustomerServiceFormData) => { + onSubmit?.({ + nickname: data.nickname || undefined, + email: data.email || undefined, + roles: data.roles || [], + }); + }; + + return ( +
+ + + + + + + + + +
+ ); + } +); diff --git a/next/web/src/App/Admin/Settings/Members/index.tsx b/next/web/src/App/Admin/Settings/Members/index.tsx index ed1c8d94c..b20e11ce4 100644 --- a/next/web/src/App/Admin/Settings/Members/index.tsx +++ b/next/web/src/App/Admin/Settings/Members/index.tsx @@ -11,18 +11,19 @@ import { useDeleteCustomerService, useUpdateCustomerService, } from '@/api/customer-service'; -import { Button, Modal, Popover, Table, message } from '@/components/antd'; +import { Button, Modal, Popover, Table, message, FormInstance } from '@/components/antd'; import { Category, Retry, UserSelect } from '@/components/common'; import { UserLabel } from '@/App/Admin/components'; import { groupBy, sortBy } from 'lodash-es'; import { RoleCheckboxGroup } from '../../components/RoleCheckboxGroup'; +import { CustomerServiceForm, CustomerServiceFormData } from './components/CustomerServiceForm'; function MemberActions({ id, nickname, active, onEdit, -}: CustomerServiceSchema & { onEdit?: () => void }) { +}: Pick & { onEdit?: () => void }) { const queryClient = useQueryClient(); const { mutate: update, isLoading: isUpdating } = useUpdateCustomerService({ @@ -133,20 +134,20 @@ function AddUserModal({ visible, onHide }: AddUserModalProps) { } interface EditUserModalRef { - open: (id: string, roles: CSRole[]) => void; + open: (id: string, data: CustomerServiceFormData) => void; } const EditUserModal = forwardRef((_, ref) => { const [userId, setUserId] = useState(); - const [roles, setRoles] = useState(); + const [data, setData] = useState(); const [visible, setVisible] = useState(false); const queryClient = useQueryClient(); useImperativeHandle(ref, () => ({ - open: (id, roles) => { + open: (id, data) => { setUserId(id); - setRoles(roles); + setData(data); setVisible(true); }, })); @@ -160,17 +161,24 @@ const EditUserModal = forwardRef((_, ref) => { }, }); + const formRef = useRef(null); + return ( update({ id: userId!, roles })} + onOk={() => formRef.current?.submit()} confirmLoading={isUpdating} - okButtonProps={{ disabled: isUpdating || !userId || roles?.length === 0 }} + okButtonProps={{ disabled: isUpdating || !userId }} onCancel={() => setVisible(false)} cancelButtonProps={{ disabled: isUpdating }} > - setRoles(v as CSRole[])} /> + update({ ...data, id: userId! })} + /> ); }); @@ -280,11 +288,17 @@ export function Members() { ( + render={(u: CustomerService) => ( { - editUserModalRef.current?.open(v.id, v.roles); + editUserModalRef.current?.open(u.id, { + nickname: u.nickname, + email: u.email, + roles: u.roles, + }); }} /> )} diff --git a/next/web/src/App/Admin/Settings/Users/index.tsx b/next/web/src/App/Admin/Settings/Users/index.tsx index 4edcab852..fb4086ee0 100644 --- a/next/web/src/App/Admin/Settings/Users/index.tsx +++ b/next/web/src/App/Admin/Settings/Users/index.tsx @@ -32,17 +32,27 @@ export function NewUser() { control={control} name="username" render={({ field }) => ( - + )} /> + ( + + + + )} + /> + ( - + )} diff --git a/next/web/src/api/customer-service.ts b/next/web/src/api/customer-service.ts index 04fabd46a..049052ded 100644 --- a/next/web/src/api/customer-service.ts +++ b/next/web/src/api/customer-service.ts @@ -48,9 +48,11 @@ async function addCustomerService(data: AddCustomerServiceData) { } export interface UpdateCustomerServiceData { + id: string; active?: boolean; roles?: CSRole[]; - id: string; + nickname?: string; + email?: string; } async function updateCustomerService({ id, ...data }: UpdateCustomerServiceData) { diff --git a/next/web/src/api/user.ts b/next/web/src/api/user.ts index b59f957ad..2289bd2e1 100644 --- a/next/web/src/api/user.ts +++ b/next/web/src/api/user.ts @@ -57,6 +57,7 @@ export const useUser = (id: string, options?: UseQueryOptions export interface CreateUserData { username?: string; + nickname?: string; email?: string; }