feat: add api to connect user completion form to backend
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
||||||
import { LocalizationProvider } from '@mui/x-date-pickers';
|
import { LocalizationProvider } from '@mui/x-date-pickers';
|
||||||
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||||
@@ -12,7 +12,6 @@ interface DateOfBirthProps {
|
|||||||
export function DateOfBirth({ value, onChange }: DateOfBirthProps) {
|
export function DateOfBirth({ value, onChange }: DateOfBirthProps) {
|
||||||
const { t, i18n } = useTranslation('completionForm');
|
const { t, i18n } = useTranslation('completionForm');
|
||||||
const isFarsi = i18n.language === 'fa' || i18n.language === 'fa-IR';
|
const isFarsi = i18n.language === 'fa' || i18n.language === 'fa-IR';
|
||||||
// const [birthDate, setBirthDate] = useState<Date | null>(null);
|
|
||||||
|
|
||||||
const Adapter = useMemo(() => {
|
const Adapter = useMemo(() => {
|
||||||
return isFarsi ? AdapterDateFnsJalali : AdapterDateFns;
|
return isFarsi ? AdapterDateFnsJalali : AdapterDateFns;
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Box, Typography } from '@mui/material';
|
import { Box, Typography } from '@mui/material';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import Logo from '@/components/Logo';
|
||||||
import { PersonalInfoFields } from './PersonalInfoFields';
|
import { PersonalInfoFields } from './PersonalInfoFields';
|
||||||
import { PasswordSection } from './PasswordSection';
|
import { PasswordSection } from './PasswordSection';
|
||||||
import { EmailSection } from './EmailSection';
|
import { EmailSection } from './EmailSection';
|
||||||
import { SubmitSection } from './SubmitSection';
|
import { SubmitSection } from './SubmitSection';
|
||||||
import Logo from '@/components/Logo';
|
|
||||||
import apiClient from '@/lib/apiClient';
|
import apiClient from '@/lib/apiClient';
|
||||||
|
import { loginWithPassword } from '@/lib/authToken';
|
||||||
|
|
||||||
export function UserCompletionForm() {
|
export function UserCompletionForm() {
|
||||||
const { t } = useTranslation('completionForm');
|
const { t } = useTranslation('completionForm');
|
||||||
|
const USERNAME = '+989353989651';
|
||||||
|
|
||||||
const [firstName, setFirstName] = useState('');
|
const [firstName, setFirstName] = useState('');
|
||||||
const [lastName, setLastName] = useState('');
|
const [lastName, setLastName] = useState('');
|
||||||
@@ -61,11 +63,9 @@ export function UserCompletionForm() {
|
|||||||
}, [password, validPassword]);
|
}, [password, validPassword]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timer: ReturnType<typeof setInterval>;
|
let timer: NodeJS.Timeout;
|
||||||
if (buttonState === 'counting' && countdown > 0) {
|
if (buttonState === 'counting' && countdown > 0) {
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => setCountdown((prev) => prev - 1), 1000);
|
||||||
setCountdown((prev) => prev - 1);
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
if (countdown === 0) {
|
if (countdown === 0) {
|
||||||
setButtonState('default');
|
setButtonState('default');
|
||||||
@@ -74,7 +74,7 @@ export function UserCompletionForm() {
|
|||||||
}, [buttonState, countdown]);
|
}, [buttonState, countdown]);
|
||||||
|
|
||||||
const toPersianDigits = (str: string) =>
|
const toPersianDigits = (str: string) =>
|
||||||
str.replace(/\d/g, (d: string) => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d)]);
|
str.replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d, 10)]);
|
||||||
|
|
||||||
const getButtonLabel = () => {
|
const getButtonLabel = () => {
|
||||||
if (buttonState === 'sent') return t('completion.sent');
|
if (buttonState === 'sent') return t('completion.sent');
|
||||||
@@ -108,40 +108,39 @@ export function UserCompletionForm() {
|
|||||||
setCodeSent(false);
|
setCodeSent(false);
|
||||||
setEmailVerified(false);
|
setEmailVerified(false);
|
||||||
};
|
};
|
||||||
const STATICTOKEN = 'Bearer abcdef1234567890';
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
setSuccess(false);
|
setSuccess(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await loginWithPassword(USERNAME, password);
|
||||||
|
|
||||||
const { data } = await apiClient.post<{
|
const { data } = await apiClient.post<{
|
||||||
success: boolean;
|
success: boolean;
|
||||||
errorCode: number;
|
errorCode: number;
|
||||||
message: string;
|
message: string;
|
||||||
validations: { property: string; message: string }[];
|
validations: { property: string; message: string }[];
|
||||||
}>(
|
}>('/User/CompleteUserInformation', {
|
||||||
'/User/CompleteUserInformation',
|
firstName,
|
||||||
{
|
lastName,
|
||||||
firstName,
|
gender: sex === 'female' ? 2 : 1,
|
||||||
lastName,
|
nationalId,
|
||||||
gender: sex === 'female' ? 2 : 1,
|
savePassword: showPasswordSection,
|
||||||
nationalId,
|
password: showPasswordSection ? password : undefined,
|
||||||
savePassword: showPasswordSection,
|
saveEmail: showEmail,
|
||||||
password: showPasswordSection ? password : undefined,
|
email: showEmail ? email : undefined,
|
||||||
saveEmail: showEmail,
|
birthDate,
|
||||||
email: showEmail ? email : undefined,
|
});
|
||||||
birthDate,
|
|
||||||
},
|
|
||||||
{ headers: { Authorization: STATICTOKEN } },
|
|
||||||
);
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
setSuccess(true);
|
setSuccess(true);
|
||||||
} else {
|
} else {
|
||||||
setError(data.message || 'Validation error');
|
setError(data.message || 'Validation error');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
setError((err as Error).message || 'An error occurred');
|
setError(err.message || 'An error occurred');
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -152,8 +151,8 @@ export function UserCompletionForm() {
|
|||||||
sx={{
|
sx={{
|
||||||
backgroundColor: 'background.default',
|
backgroundColor: 'background.default',
|
||||||
minHeight: '100vh',
|
minHeight: '100vh',
|
||||||
flexDirection: 'column',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
p: { xs: 1, sm: 2, md: 3 },
|
p: { xs: 1, sm: 2, md: 3 },
|
||||||
@@ -165,7 +164,7 @@ export function UserCompletionForm() {
|
|||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: '730px',
|
maxWidth: 730,
|
||||||
backgroundColor: 'background.paper',
|
backgroundColor: 'background.paper',
|
||||||
border: '1px solid #ccc',
|
border: '1px solid #ccc',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -175,14 +174,7 @@ export function UserCompletionForm() {
|
|||||||
py: { xs: 3, sm: 4 },
|
py: { xs: 3, sm: 4 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
width: '100%',
|
|
||||||
gap: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="h5" color="text.primary">
|
<Typography variant="h5" color="text.primary">
|
||||||
{t('completion.title')}
|
{t('completion.title')}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -190,6 +182,7 @@ export function UserCompletionForm() {
|
|||||||
{t('completion.description')}
|
{t('completion.description')}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<PersonalInfoFields
|
<PersonalInfoFields
|
||||||
firstName={firstName}
|
firstName={firstName}
|
||||||
setFirstName={setFirstName}
|
setFirstName={setFirstName}
|
||||||
@@ -204,6 +197,7 @@ export function UserCompletionForm() {
|
|||||||
country={country}
|
country={country}
|
||||||
setCountry={setCountry}
|
setCountry={setCountry}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PasswordSection
|
<PasswordSection
|
||||||
showPasswordSection={showPasswordSection}
|
showPasswordSection={showPasswordSection}
|
||||||
setShowPasswordSection={setShowPasswordSection}
|
setShowPasswordSection={setShowPasswordSection}
|
||||||
@@ -219,6 +213,7 @@ export function UserCompletionForm() {
|
|||||||
validPassword={validPassword}
|
validPassword={validPassword}
|
||||||
showValidations={showPasswordValidations}
|
showValidations={showPasswordValidations}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EmailSection
|
<EmailSection
|
||||||
showEmail={showEmail}
|
showEmail={showEmail}
|
||||||
setShowEmail={setShowEmail}
|
setShowEmail={setShowEmail}
|
||||||
@@ -236,6 +231,7 @@ export function UserCompletionForm() {
|
|||||||
isVerifyingCode={isVerifyingCode}
|
isVerifyingCode={isVerifyingCode}
|
||||||
handleEditEmail={handleEditEmail}
|
handleEditEmail={handleEditEmail}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SubmitSection
|
<SubmitSection
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
34
src/lib/authToken.ts
Normal file
34
src/lib/authToken.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// src/lib/authService.ts
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export interface TokenResponse {
|
||||||
|
access_token: string;
|
||||||
|
expires_in: number;
|
||||||
|
refresh_token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authClient = axios.create({
|
||||||
|
baseURL: 'https://account.business-harmony.com',
|
||||||
|
timeout: 10000,
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function loginWithPassword(
|
||||||
|
username: string,
|
||||||
|
password: string,
|
||||||
|
): Promise<TokenResponse> {
|
||||||
|
const body = new URLSearchParams();
|
||||||
|
body.set('grant_type', 'password');
|
||||||
|
body.set('username', username);
|
||||||
|
body.set('password', password);
|
||||||
|
body.set('client_id', 'harmony_identity');
|
||||||
|
body.set('scope', 'openid harmony_identity profile offline_access');
|
||||||
|
|
||||||
|
const { data } = await authClient.post<TokenResponse>(
|
||||||
|
'/connect/token',
|
||||||
|
body.toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
localStorage.setItem('authToken', data.access_token);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user