Skip to content

Instantly share code, notes, and snippets.

@7iomka
Created September 6, 2023 11:40
Show Gist options
  • Save 7iomka/ae496d62d17e52c5016aaaa79f2facf4 to your computer and use it in GitHub Desktop.
Save 7iomka/ae496d62d17e52c5016aaaa79f2facf4 to your computer and use it in GitHub Desktop.
import clsx from 'clsx';
import { Anchor, Button, Loader, LoadingOverlay } from '@mantine/core';
import type { PropsWithChildren } from 'react';
import { useUnit } from 'effector-react';
import { $$viewer } from '@/entities/viewer';
import { Form, FormField, useForm } from '@/shared/form';
import { createView } from '@/shared/lib/view';
import { CustomLink } from '@/shared/ui';
import { createModelProvider2 } from '@/shared/lib/factory';
import { factory } from '../../register.model';
const { ModelProvider: CreateRegisterFormProvider, useModel } =
createModelProvider2('RegisterFormProvider');
const FormPhone = createView()
.map(() => {
const model = useModel(factory);
const [isLoading, isPhoneEditable, handleEditPhone, confirmationModes] = useUnit([
model.$formPhonePending,
model.$isPhoneEditable,
model.editPhoneClicked,
model.$confirmationModes,
]);
const { fields, onSubmit: handleSubmit } = useForm(model.$$formPhone);
return {
fields,
handleSubmit,
isLoading,
isPhoneEditable,
handleEditPhone,
confirmationModes,
};
})
.view(
({ fields, handleSubmit, isLoading, isPhoneEditable, handleEditPhone, confirmationModes }) => (
<Form onSubmit={handleSubmit}>
<FormField.PhoneInput
field={fields.phone}
label="Номер телефона"
disabled={!isPhoneEditable}
/>
{!isPhoneEditable && (
<Anchor
component="button"
type="button"
color="dark"
underline
className="opacity-70 hover:opacity-100 mt-5"
onClick={handleEditPhone}
>
Изменить номер телефона
</Anchor>
)}
{isPhoneEditable && (
<>
<FormField.SegmentedControl
className="mt-15"
field={fields.confirmationMode}
data={confirmationModes.map((mode) => ({
value: mode.value,
label: mode.label,
}))}
fullWidth
color="primary"
/>
<Button
radius="xl"
color="gray.3"
fullWidth
className="mt-15"
disabled={isLoading}
type="submit"
>
{isLoading ? <Loader variant="dots" color="dark" /> : 'Получить код'}
</Button>
</>
)}
</Form>
),
);
const FormPhoneConfirm = createView<
PropsWithChildren<{ className?: string; submitLabel?: string }>
>()
.map(() => {
const model = useModel(factory);
const [
isLoading,
isConfirmationCountdownRunning,
confirmationCodeRequestCount,
confirmationCountdown,
resendCode,
confirmationModeInfo,
] = useUnit([
model.$registerPending,
model.$isPhoneConfirmationCountdownRunning,
model.$confirmationCodeRequestCount,
model.$phoneConfirmationCountdownString,
model.confirmationCodeResended,
model.$confirmationModeInfo,
]);
const { fields, onSubmit: handleSubmit } = useForm(model.$$formPhoneConfirm);
return {
fields,
handleSubmit,
isLoading,
isConfirmationCountdownRunning,
confirmationCountdown,
confirmationCodeRequestCount,
resendCode,
confirmationModeInfo,
};
})
.view(
({
className,
fields,
handleSubmit,
isLoading,
isConfirmationCountdownRunning,
confirmationCountdown,
confirmationCodeRequestCount,
resendCode,
confirmationModeInfo,
submitLabel = 'Зарегистрироваться',
children,
}) => (
<div className={className}>
<Form className={className} onSubmit={handleSubmit}>
<div className="text-sm text-center font-bold">
Минутку, код подтверждения отправлен на указанный номер через{' '}
{confirmationModeInfo.label}.
</div>
<FormField.TextInput
className="mt-20"
field={fields.code}
label="Код из сообщения"
autoComplete="off"
/>
{!!children && <div className="mt-15">{children}</div>}
<FormField.Checkbox
className="mt-20"
field={fields.agreement}
label={
<>
Согласен с{' '}
<CustomLink
className="inline"
component="a"
href="/static/documents/privacy-policy.pdf"
target="_blank"
>
правилами обработки персональных данных
</CustomLink>
</>
}
/>
<Button radius="xl" className="mt-15" fullWidth type="submit">
{isLoading ? <Loader variant="dots" color="dark" /> : submitLabel}
</Button>
{confirmationCodeRequestCount > 0 &&
(isConfirmationCountdownRunning ? (
<div className="text-sm text-center font-bold mt-10">
Получить код повторно через {confirmationCountdown}
</div>
) : (
<Button radius="xl" className="mt-15" color="gray.3" fullWidth onClick={resendCode}>
Получить новый код
</Button>
))}
</Form>
</div>
),
);
const RegisterForm = createView<
PropsWithChildren<{
className?: string;
formSubmitLabel?: string;
}>
>()
.displayName('RegisterForm')
.units({
isAuthorized: $$viewer.$isAuthorized,
})
.map(() => {
const model = useModel(factory);
const isConfirmationCodeEnabled = useUnit(model.$isConfirmationCodeEnabled);
return { isConfirmationCodeEnabled };
})
.memo()
.view(({ className, isConfirmationCodeEnabled, children, formSubmitLabel, isAuthorized }) => (
<section className={clsx(className, 'relative')}>
<FormPhone />
{isConfirmationCodeEnabled && (
<FormPhoneConfirm className="mt-15" submitLabel={formSubmitLabel}>
{children}
</FormPhoneConfirm>
)}
<LoadingOverlay
visible={isAuthorized}
loader={
<div className="flex-col items-center text-center">
<Loader width={40} variant="dots" />
</div>
}
/>
</section>
)).Memo;
const CreateRegisterForm = ({ model, ...rest }) => (
<CreateRegisterFormProvider model={model}>
<RegisterForm {...rest} />
</CreateRegisterFormProvider>
);
export { CreateRegisterForm };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment