chore: change styles and add Api for user profile

This commit is contained in:
Koosha Lahouti
2025-08-12 20:20:28 +03:30
parent ed57858c2e
commit 782ef2a2de
35 changed files with 2785 additions and 1843 deletions

View File

@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { CardContainer } from '@/components/CardContainer';
import { PageWrapper } from '../PageWrapper';
@@ -7,13 +7,53 @@ import SocialMediaMenu from './socialMedia/SocialMediaMenu';
import SocialMediaDialog from './socialMedia/SocialMediaDialog';
import useMediaQuery from '@mui/material/useMediaQuery';
import type { Theme } from '@mui/material/styles';
import apiClient from '@/lib/apiClient';
import { Box, CircularProgress, Typography } from '@mui/material';
interface EmailAccount {
email: string;
provider: 'email' | 'google';
time: string;
}
interface GetProfileApiResponse {
success: boolean;
message?: string;
email?: string;
}
interface SendCodeApiResponse {
success: boolean;
message?: string;
}
interface ConfirmCodeApiResponse {
success: boolean;
confirm?: boolean;
message?: string;
}
interface ChangeEmailApiResponse {
success: boolean;
message?: string;
}
export function SocialMedia() {
const { t } = useTranslation('profileSetting');
const { t } = useTranslation('setting');
const token = localStorage.getItem('authToken');
const [openDialog, setOpenDialog] = useState(false);
const [emailInput, setEmailInput] = useState('');
const [emailError, setEmailError] = useState(false);
const [verificationCode, setVerificationCode] = useState('');
const [dialogStep, setDialogStep] = useState<'enterEmail' | 'enterCode'>(
'enterEmail',
);
const [apiError, setApiError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [emailList, setEmailList] = useState<EmailAccount[]>([]);
const [isFetching, setIsFetching] = useState(true);
const [fetchError, setFetchError] = useState<string | null>(null);
const fullScreen = useMediaQuery((theme: Theme) =>
theme.breakpoints.down('sm'),
@@ -26,10 +66,128 @@ export function SocialMedia() {
| 'lg'
| 'xl';
const emailList = [
{ email: 'emailtemp@email.com', provider: 'email', time: '1 ماه پیش' },
{ email: 'emailtemp@gmail.com', provider: 'google', time: '1 ماه پیش' },
] as const;
useEffect(() => {
const fetchInitialEmail = async () => {
setIsFetching(true);
setFetchError(null);
if (!token) {
setIsFetching(false);
setFetchError(t('settingForm.notLoggedIn'));
return;
}
try {
const res = await apiClient.post<GetProfileApiResponse>(
'/Profile/GetProfile',
{},
{ headers: { Authorization: `Bearer ${token}` } },
);
if (res.data.success && res.data.email) {
const userEmail = res.data.email;
const newAccount: EmailAccount = {
email: userEmail,
provider: userEmail.includes('gmail.com') ? 'google' : 'email',
time: '',
};
setEmailList([newAccount]);
} else if (!res.data.success) {
throw new Error(res.data.message || t('settingForm.failFetchEmail'));
}
} catch (err: unknown) {
let message = t('settingForm.errorFetchEmail');
if (err instanceof Error) {
message = err.message;
}
setFetchError(message);
} finally {
setIsFetching(false);
}
};
fetchInitialEmail();
}, [token, t]);
const resetDialog = () => {
setOpenDialog(false);
setEmailInput('');
setVerificationCode('');
setApiError(null);
setIsLoading(false);
setDialogStep('enterEmail');
};
const handleSendCode = async () => {
if (!/^\S+@\S+\.\S+$/.test(emailInput)) {
setApiError(t('settingForm.emailIsInvalid'));
return;
}
setIsLoading(true);
setApiError(null);
try {
const res = await apiClient.post<SendCodeApiResponse>(
'Profile/SendEmailChangeCode',
{ email: emailInput },
{ headers: { Authorization: `Bearer ${token}` } },
);
if (res.data.success) {
setDialogStep('enterCode');
} else {
setApiError(res.data.message || t('settingForm.sendCodeFailed'));
}
} catch (err: unknown) {
setApiError(t('settingForm.sendCodeFailed'));
} finally {
setIsLoading(false);
}
};
const handleConfirmAndChangeEmail = async () => {
if (verificationCode.length < 4) {
setApiError(t('settingForm.verificationCodeRequired'));
return;
}
setIsLoading(true);
setApiError(null);
try {
const confirmRes = await apiClient.post<ConfirmCodeApiResponse>(
'Profile/ConfirmEmailChangeCode',
{ email: emailInput, verifyCode: verificationCode },
{ headers: { Authorization: `Bearer ${token}` } },
);
if (confirmRes.data.success && confirmRes.data.confirm) {
const changeRes = await apiClient.post<ChangeEmailApiResponse>(
'Profile/ChangeEmail',
{ email: emailInput },
{ headers: { Authorization: `Bearer ${token}` } },
);
if (changeRes.data.success) {
setEmailList((prevList) => [
...prevList,
{
email: emailInput,
provider: 'email',
time: t('settingForm.justNow'),
},
]);
resetDialog();
} else {
setApiError(
changeRes.data.message || t('settingForm.changeEmailFailed'),
);
}
} else {
setApiError(
confirmRes.data.message || t('settingForm.verifyCodeFailed'),
);
}
} catch (err: unknown) {
setApiError(t('settingForm.anErrorOccurred'));
} finally {
setIsLoading(false);
}
};
return (
<PageWrapper>
@@ -40,15 +198,38 @@ export function SocialMedia() {
<SocialMediaMenu t={t} onOpenDialog={() => setOpenDialog(true)} />
}
>
<SocialMediaList t={t} emailList={emailList} />
{isFetching ? (
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
p: 4,
minHeight: '100px',
}}
>
<CircularProgress />
</Box>
) : fetchError ? (
<Box sx={{ textAlign: 'center', p: 4 }}>
<Typography color="error.main">{fetchError}</Typography>
</Box>
) : (
<SocialMediaList t={t} emailList={emailList} />
)}
<SocialMediaDialog
open={openDialog}
onClose={() => setOpenDialog(false)}
onClose={resetDialog}
t={t}
emailInput={emailInput}
setEmailInput={setEmailInput}
emailError={emailError}
setEmailError={setEmailError}
verificationCode={verificationCode}
setVerificationCode={setVerificationCode}
apiError={apiError}
isLoading={isLoading}
dialogStep={dialogStep}
onSendCode={handleSendCode}
onConfirmEmail={handleConfirmAndChangeEmail}
fullScreen={fullScreen}
computedMaxWidth={computedMaxWidth}
/>