Untitled

mail@pastecode.io avatarunknown
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>
  );
}