206 lines
5.6 KiB
TypeScript
206 lines
5.6 KiB
TypeScript
import { useState, useEffect, useMemo } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { CardContainer } from '@/components/CardContainer';
|
|
import { PageWrapper } from '../PageWrapper';
|
|
import SocialMediaList from './socialMedia/SocialMediaList';
|
|
import SocialMediaMenu from './socialMedia/SocialMediaMenu';
|
|
import SocialMediaDialog from './socialMedia/SocialMediaDialog';
|
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
|
import type { Theme } from '@mui/material/styles';
|
|
import { Box, CircularProgress, Typography } from '@mui/material';
|
|
import { useManualApi } from '@/hooks/useApi';
|
|
import {
|
|
fetchProfile,
|
|
sendEmailCode,
|
|
confirmEmailCode,
|
|
changeEmail,
|
|
} from '../../api/settingsApi';
|
|
|
|
interface EmailAccount {
|
|
email: string;
|
|
provider: 'email' | 'google';
|
|
time: string;
|
|
}
|
|
|
|
export function SocialMedia() {
|
|
const { t } = useTranslation('setting');
|
|
|
|
const [openDialog, setOpenDialog] = useState(false);
|
|
const [emailInput, setEmailInput] = useState('');
|
|
const [verificationCode, setVerificationCode] = useState('');
|
|
const [dialogStep, setDialogStep] = useState<'enterEmail' | 'enterCode'>(
|
|
'enterEmail',
|
|
);
|
|
const [emailList, setEmailList] = useState<EmailAccount[]>([]);
|
|
const [formError, setFormError] = useState<string | null>(null);
|
|
|
|
const {
|
|
data: profileData,
|
|
loading: isFetching,
|
|
error: fetchError,
|
|
execute: executeFetchProfile,
|
|
} = useManualApi(fetchProfile);
|
|
|
|
const {
|
|
data: sendCodeData,
|
|
loading: isSendingCode,
|
|
error: sendCodeError,
|
|
execute: executeSendCode,
|
|
} = useManualApi(sendEmailCode);
|
|
|
|
const {
|
|
data: confirmData,
|
|
loading: isConfirming,
|
|
error: confirmError,
|
|
execute: executeConfirmCode,
|
|
} = useManualApi(confirmEmailCode);
|
|
|
|
const {
|
|
data: changeEmailData,
|
|
loading: isChangingEmail,
|
|
error: changeEmailError,
|
|
execute: executeChangeEmail,
|
|
} = useManualApi(changeEmail);
|
|
|
|
const fullScreen = useMediaQuery((theme: Theme) =>
|
|
theme.breakpoints.down('sm'),
|
|
);
|
|
const downMd = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'));
|
|
const computedMaxWidth = (fullScreen ? 'xs' : downMd ? 'sm' : 'md') as
|
|
| 'xs'
|
|
| 'sm'
|
|
| 'md'
|
|
| 'lg'
|
|
| 'xl';
|
|
|
|
useEffect(() => {
|
|
executeFetchProfile();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (profileData?.success && profileData.email) {
|
|
const { email } = profileData;
|
|
setEmailList([
|
|
{
|
|
email,
|
|
provider: email.includes('@gmail.') ? 'google' : 'email',
|
|
time: '',
|
|
},
|
|
]);
|
|
}
|
|
}, [profileData]);
|
|
|
|
useEffect(() => {
|
|
if (sendCodeData?.success) {
|
|
setDialogStep('enterCode');
|
|
}
|
|
}, [sendCodeData]);
|
|
|
|
useEffect(() => {
|
|
if (confirmData?.success && confirmData.confirm) {
|
|
executeChangeEmail({ email: emailInput });
|
|
}
|
|
}, [confirmData, emailInput, executeChangeEmail]);
|
|
|
|
useEffect(() => {
|
|
if (changeEmailData?.success) {
|
|
setEmailList((prev) => [
|
|
...prev,
|
|
{
|
|
email: emailInput,
|
|
provider: emailInput.includes('@gmail.') ? 'google' : 'email',
|
|
time: t('settingForm.justNow'),
|
|
},
|
|
]);
|
|
resetDialog();
|
|
}
|
|
}, [changeEmailData, emailInput, t]);
|
|
|
|
const resetDialog = () => {
|
|
setOpenDialog(false);
|
|
setEmailInput('');
|
|
setVerificationCode('');
|
|
setFormError(null);
|
|
setDialogStep('enterEmail');
|
|
};
|
|
|
|
const handleSendCode = () => {
|
|
if (!/^\S+@\S+\.\S+$/.test(emailInput)) {
|
|
setFormError(t('settingForm.emailIsInvalid'));
|
|
return;
|
|
}
|
|
setFormError(null);
|
|
executeSendCode({ email: emailInput });
|
|
};
|
|
|
|
const handleConfirmAndChangeEmail = () => {
|
|
if (verificationCode.length < 4) {
|
|
setFormError(t('settingForm.verificationCodeRequired'));
|
|
return;
|
|
}
|
|
setFormError(null);
|
|
executeConfirmCode({ email: emailInput, verifyCode: verificationCode });
|
|
};
|
|
|
|
const getErrorMessage = (error: unknown): string | null => {
|
|
if (!error) return null;
|
|
if (error instanceof Error) return error.message;
|
|
return String(error);
|
|
};
|
|
|
|
const apiError = useMemo(
|
|
() => getErrorMessage(sendCodeError || confirmError || changeEmailError),
|
|
[sendCodeError, confirmError, changeEmailError],
|
|
);
|
|
|
|
return (
|
|
<PageWrapper>
|
|
<CardContainer
|
|
title={t('settingForm.titleSocial')}
|
|
subtitle={t('settingForm.descriptionSocial')}
|
|
action={
|
|
<SocialMediaMenu t={t} onOpenDialog={() => setOpenDialog(true)} />
|
|
}
|
|
>
|
|
{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">
|
|
{getErrorMessage(fetchError)}
|
|
</Typography>
|
|
</Box>
|
|
) : (
|
|
<SocialMediaList t={t} emailList={emailList} />
|
|
)}
|
|
<SocialMediaDialog
|
|
open={openDialog}
|
|
onClose={resetDialog}
|
|
t={t}
|
|
emailInput={emailInput}
|
|
setEmailInput={setEmailInput}
|
|
verificationCode={verificationCode}
|
|
setVerificationCode={setVerificationCode}
|
|
apiError={formError || apiError}
|
|
isLoading={isSendingCode || isConfirming || isChangingEmail}
|
|
dialogStep={dialogStep}
|
|
onSendCode={handleSendCode}
|
|
onConfirmEmail={handleConfirmAndChangeEmail}
|
|
fullScreen={fullScreen}
|
|
computedMaxWidth={computedMaxWidth}
|
|
/>
|
|
</CardContainer>
|
|
</PageWrapper>
|
|
);
|
|
}
|