Untitled
plain_text
a month ago
12 kB
3
Indexable
Never
import React from 'react'; import { Text, Input, FormControl, FormErrorMessage, Switch, VStack, Button, Flex, HStack, Spacer, Icon, useToast, } from '@chakra-ui/react'; import AdminLayout from 'layouts/admin'; import { useRouter } from 'next/router'; import { useTranslation } from 'react-i18next'; import { FormGroup } from 'components'; import { Formik } from 'formik'; import * as yup from 'yup'; import { useAppDispatch } from 'store/store'; import { setAppLoading } from 'store/slices/appSlice'; import { EMode, RoleTypeEnum } from 'constant'; import { debounce } from 'lodash'; import { Select, chakraComponents, ChakraStylesConfig } from 'chakra-react-select'; import { IconArrowDown } from 'components/icons/Icons'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { GetListPartnerResponse, createAccount, getAccount, getPartners, updateAccount, } from 'api/account'; import { IPartner } from 'types/model'; import { error, success } from 'utils/toast'; type SelectRoleType = { label: string; value: RoleTypeEnum; }; interface FormValues { id: string; username: string; password: string; email: string; partner: IPartner | null; role: SelectRoleType | null; locked: boolean; mode: EMode | null; } const initialValues: FormValues = { id: '', username: '', password: '', email: '', partner: undefined, role: undefined, locked: true, mode: EMode.CREATE, }; export default function CreateUpdateAccount() { const router = useRouter(); const toast = useToast(); const dispatch = useAppDispatch(); const queryClient = useQueryClient(); const { t } = useTranslation(['common', 'account']); const id = router.query ? router.query : undefined; const { data: partners } = useQuery<GetListPartnerResponse>({ queryKey: ['list-partner'], queryFn: getPartners, retry: 1, }); const roles: SelectRoleType[] = [ { label: t('common:customer'), value: RoleTypeEnum.CUSTOMER, }, { label: t('common:provider'), value: RoleTypeEnum.PROVIDER, }, ]; const customComponents = { DropdownIndicator: (props: any) => ( <chakraComponents.DropdownIndicator {...props}> <Icon as={IconArrowDown} w="12px" /> </chakraComponents.DropdownIndicator> ), Option: (props: any) => { const { isFocused } = props; return ( <chakraComponents.Option {...props}> <Text color={isFocused ? 'primary' : 'text-title'}>{props.children}</Text> </chakraComponents.Option> ); }, }; const chakraStyles: ChakraStylesConfig = { dropdownIndicator: (provided, state) => ({ ...provided, p: 0, borderRight: '0px', borderWidth: '1px', color: state.isFocused ? 'primary' : 'text-note', marginLeft: '-1px', borderColor: 'bg-1', w: '40px', }), }; const { mutate: createAccountMutate } = useMutation({ mutationKey: ['create-account'], mutationFn: createAccount, retry: 1, onSuccess: () => { queryClient.invalidateQueries(['list-account']); dispatch(setAppLoading(false)); toast( success({ title: t('common:create_successfully'), onCloseComplete: () => { router.back(); }, }) ); }, onError: () => { dispatch(setAppLoading(false)); toast(error({ title: t('common:create_failed') })); }, }); const { mutate: updateAccountMutate } = useMutation({ mutationKey: ['update-account'], mutationFn: updateAccount, retry: 1, onSuccess: () => { queryClient.invalidateQueries(['list-account']); dispatch(setAppLoading(false)); toast( success({ title: t('common:update_successfully'), onCloseComplete: () => { router.back(); }, }) ); }, onError: () => { dispatch(setAppLoading(false)); toast(error({ title: t('common:update_failed') })); }, }); const { mutate: getAccountMutate } = useMutation({ mutationKey: ['get-account'], mutationFn: getAccount, retry: 1, }); const handleSubmitVoucher = React.useCallback( async ({ mode, id, username, email, password, partner, role, locked }: FormValues) => { dispatch(setAppLoading(true)); if (mode === EMode.EDIT) { createAccountMutate({ username: username, email: email, password: password, partnerId: partner.id, role: role.value, locked: locked, }); } else { updateAccountMutate({ id: id, username: username, partnerId: partner.id, role: role.value, locked: locked, }); } }, [] ); const validationSchema = yup.object().shape({ username: yup.string().required(t('common:error_field_empty')), email: yup.string().required(t('common:error_field_empty')).email(t('common:invalid_email')), password: yup.string().required(t('common:error_field_empty')), partner: yup.object().shape({ label: yup.string().required(t('common:error_field_empty')), value: yup.number().required(t('common:error_field_empty')), }), role: yup.object().shape({ label: yup.string().required(t('common:error_field_empty')), value: yup.string().required(t('common:error_field_empty')), }), }); return ( <Formik validateOnChange={false} validationSchema={validationSchema} enableReinitialize={true} initialValues={initialValues} onSubmit={handleSubmitVoucher}> {({ handleChange, handleSubmit, setFieldValue, validateField, values, errors, dirty }) => { const validateDebounced = debounce(validateField, 300); React.useEffect(() => { if (router.query.mode) { setFieldValue('mode', router.query.mode); } }, [router.query.mode]); React.useEffect(() => { if (router.query.mode) { setFieldValue('mode', router.query.mode); } }, [router.query.mode]); getAccountMutate; // username: username, // email: email, // password: password, // partnerId: partner.id, // role: role.value, // locked: locked, //TODO: when mode = edit if dirty then submit, if not router back //console.log('quang debug dirty', dirty); return ( <AdminLayout> <Flex flexDirection="column" pt={{ base: '12px', md: '90px', xl: '90px' }} minH="90vh"> <Text color="title-title" textStyle="h4-sb" textTransform="uppercase"> {values.mode === EMode.CREATE ? t('account:add_new_account') : values.mode === EMode.EDIT ? t('account:edit_account') : t('account:account_information')} </Text> <VStack spacing="6" mt="6" alignItems="normal" maxW="5xl" mx="auto" w="100%"> <FormGroup isRequire title={t('common:user_name')}> <FormControl isInvalid={!!errors.username}> <Input id="username" name="username" placeholder={t('account:input_username')} autoComplete="off" value={values.username} onChange={(e) => { handleChange(e); validateDebounced('username'); }} maxLength={120} /> <FormErrorMessage>{errors.username}</FormErrorMessage> </FormControl> </FormGroup> <FormGroup isRequire title={t('common:email')}> <FormControl isInvalid={!!errors.email}> <Input id="email" name="email" type="email" placeholder={t('account:input_email')} autoComplete="off" value={values.email} onChange={(e) => { handleChange(e); validateDebounced('email'); }} /> <FormErrorMessage>{errors.email}</FormErrorMessage> </FormControl> </FormGroup> <FormGroup isRequire title={t('common:password')}> <FormControl isInvalid={!!errors.password}> <Input type="password" id="password" name="password" placeholder={t('account:input_password')} autoComplete="off" value={values.password} onChange={(e) => { handleChange(e); validateDebounced('password'); }} /> <FormErrorMessage>{errors.password}</FormErrorMessage> </FormControl> </FormGroup> <FormGroup isRequire title={t('common:partner')}> <FormControl isInvalid={!!errors.partner}> <Select id="partner" name="partner" instanceId="partner" inputId="partner" chakraStyles={chakraStyles} options={partners?.data as any} value={values.partner} onChange={(e) => { setFieldValue('partner', e); validateDebounced('partner'); }} placeholder={t('account:select_partner')} components={customComponents} /> <FormErrorMessage>{errors.partner.id}</FormErrorMessage> </FormControl> </FormGroup> <FormGroup isRequire title={t('common:role')}> <FormControl isInvalid={!!errors.role}> <Select id="role" name="role" instanceId="role" inputId="role" chakraStyles={chakraStyles} options={roles} value={values.role} onChange={(e) => { setFieldValue('role', e); validateDebounced('role'); }} placeholder={t('account:select_role')} components={customComponents} /> <FormErrorMessage>{errors.role.value}</FormErrorMessage> </FormControl> </FormGroup> <FormGroup title={t('common:status')}> <Switch id="locked" name="locked" isChecked={values.locked} onChange={handleChange('locked')} variant="success" /> </FormGroup> </VStack> <Spacer /> <HStack mt="6" gap="8" w="100%" maxW="xl" mx="auto"> <Button flex="1" variant="outline" children={t('common:back')} onClick={() => router.back()} /> <Button flex="1" children={ values.mode === EMode.DETAIL ? t('common:edit_information') : t('common:save_information') } onClick={() => { if (values.mode === EMode.DETAIL) { setFieldValue('mode', EMode.EDIT); } else { handleSubmit(); } }} /> </HStack> </Flex> </AdminLayout> ); }} </Formik> ); }