Implement Auth account page
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
import { createContext, useState, useEffect } from "react";
|
||||
import { TokenType } from "@/types/user";
|
||||
import { TokenProps } from "@/types/user";
|
||||
import { useRouter, usePathname } from "@/src/navigation";
|
||||
|
||||
const LOCAL_STORAGE_KEY = "testplat-auth-token";
|
||||
const privatePaths = ["/account"];
|
||||
|
||||
function storeTokenToLocalStorage(token: TokenType) {
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(token));
|
||||
@@ -16,7 +18,10 @@ function removeTokenFromLocalStorage() {
|
||||
const defaultTokenContext = {};
|
||||
const TokenContext = createContext(defaultTokenContext);
|
||||
|
||||
const TokenProvider = ({ children }: TokenProps) => {
|
||||
const TokenProvider = ({ locale, children }: TokenProps) => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const [token, setToken] = useState<TokenType>({
|
||||
access_token: "",
|
||||
user: null,
|
||||
@@ -28,13 +33,27 @@ const TokenProvider = ({ children }: TokenProps) => {
|
||||
removeTokenFromLocalStorage,
|
||||
};
|
||||
|
||||
const restoreTokenFromLocalStorage = () => {
|
||||
const tokenString = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (tokenString) {
|
||||
const restoredToken = JSON.parse(tokenString);
|
||||
setToken(restoredToken);
|
||||
} else {
|
||||
checkSignInPage();
|
||||
}
|
||||
};
|
||||
|
||||
const checkSignInPage = () => {
|
||||
if (
|
||||
privatePaths.some((path) => {
|
||||
return path === pathname;
|
||||
})
|
||||
) {
|
||||
router.push(`/account/signin`, { locale: locale });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const restoreTokenFromLocalStorage = () => {
|
||||
const tokenString = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (tokenString) {
|
||||
setToken(JSON.parse(tokenString));
|
||||
}
|
||||
};
|
||||
restoreTokenFromLocalStorage();
|
||||
}, []);
|
||||
|
||||
|
||||
46
frontend/src/app/[locale]/account/AccountPage.tsx
Normal file
46
frontend/src/app/[locale]/account/AccountPage.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
"use client";
|
||||
import { useContext } from "react";
|
||||
import { Avatar, Card, CardHeader, CardBody, Divider } from "@nextui-org/react";
|
||||
import { TokenContext } from "../TokenProvider";
|
||||
|
||||
type AccountPageMessages = {
|
||||
yourProjects: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
messages: AccountPageMessages;
|
||||
locale: string;
|
||||
};
|
||||
|
||||
export default function AccountPage({ messages, locale }: Props) {
|
||||
const context = useContext(TokenContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
{context.token && context.token.user && (
|
||||
<Card className="w-[600px] mt-16 mx-3">
|
||||
<CardHeader className="flex gap-6">
|
||||
<Avatar
|
||||
isBordered
|
||||
radius="full"
|
||||
className="w-16 h-16 text-large"
|
||||
src={context.token.user.avatarPath}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<p className="text-2xl font-bold">
|
||||
{context.token.user.username}
|
||||
</p>
|
||||
<p className="text-lg text-default-500">
|
||||
{context.token.user.email}
|
||||
</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<Divider />
|
||||
<CardBody className="overflow-visible px-4 pb-4">
|
||||
<p className="text-default-500">{messages.yourProjects}</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { UserType } from "@/types/user";
|
||||
import { avatars } from "@/config/selection";
|
||||
import Config from "@/config/config";
|
||||
const apiServer = Config.apiServer;
|
||||
|
||||
@@ -50,4 +51,9 @@ async function signIn(signInUser: UserType) {
|
||||
}
|
||||
}
|
||||
|
||||
export { signUp, signIn };
|
||||
function getRandomAvatarPath() {
|
||||
const randomIndex = Math.floor(Math.random() * avatars.length);
|
||||
return avatars[randomIndex];
|
||||
}
|
||||
|
||||
export { signUp, signIn, getRandomAvatarPath };
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Link } from "@/src/navigation";
|
||||
import { ChevronRight, Eye, EyeOff } from "lucide-react";
|
||||
import { UserType, AuthMessages } from "@/types/user";
|
||||
import { roles } from "@/config/selection";
|
||||
import { signUp, signIn } from "./authControl";
|
||||
import { signUp, signIn, getRandomAvatarPath } from "./authControl";
|
||||
import { isValidEmail, isValidPassword } from "./validate";
|
||||
import { TokenContext } from "../TokenProvider";
|
||||
import { useRouter } from "@/src/navigation";
|
||||
@@ -58,6 +58,8 @@ export default function AuthPage({ isSignup, messages, locale }: Props) {
|
||||
}
|
||||
}
|
||||
|
||||
const initialavatarPath = getRandomAvatarPath();
|
||||
user.avatarPath = initialavatarPath;
|
||||
await submit();
|
||||
};
|
||||
|
||||
@@ -85,7 +87,7 @@ export default function AuthPage({ isSignup, messages, locale }: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="border-none bg-background/60 dark:bg-default-100/50 w-[480px]">
|
||||
<Card className="w-[480px] mt-16">
|
||||
<CardHeader className="px-4 pt-4 pb-0 flex justify-between">
|
||||
<h4 className="font-bold text-large">{messages.title}</h4>
|
||||
<Link
|
||||
|
||||
@@ -1,27 +1,10 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Input, Button, Card, CardHeader, CardBody } from "@nextui-org/react";
|
||||
import { Link } from "@/src/navigation";
|
||||
|
||||
import AccountPage from "./AccountPage";
|
||||
export default function Page(params: { locale: string }) {
|
||||
const t = useTranslations("Auth");
|
||||
const messages = {
|
||||
yourProjects: t("your_projects"),
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="border-none bg-background/60 dark:bg-default-100/50 w-[480px]">
|
||||
<CardHeader className="px-4 pt-4 pb-0 flex justify-between">
|
||||
<h4 className="font-bold text-large">{t('account')}</h4>
|
||||
{/* <Link href={isSignup ? "/auth/signin" : "/auth/signup"} locale={locale}>
|
||||
<Button
|
||||
color="primary"
|
||||
variant="light"
|
||||
endContent={<ChevronRight size={16} />}
|
||||
>
|
||||
{messages.linkTitle}
|
||||
</Button>
|
||||
</Link> */}
|
||||
</CardHeader>
|
||||
<CardBody className="overflow-visible px-4 pt-0 pb-4">
|
||||
afgdsfg
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
return <AccountPage messages={messages} locale={params.locale} />;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,10 @@ export default function RootLayout({
|
||||
fontSans.variable
|
||||
)}
|
||||
>
|
||||
<Providers themeProps={{ attribute: "class", defaultTheme: "light" }}>
|
||||
<Providers
|
||||
themeProps={{ attribute: "class", defaultTheme: "light" }}
|
||||
tokenProps={{ locale: locale }}
|
||||
>
|
||||
<div className="relative flex flex-col min-h-screen light:bg-neutral-50 dark:bg-neutral-800">
|
||||
<Header locale={locale} />
|
||||
<main>{children}</main>
|
||||
|
||||
@@ -12,16 +12,16 @@ import { TokenProps } from "@/types/user";
|
||||
export interface ProvidersProps {
|
||||
children: React.ReactNode;
|
||||
themeProps?: ThemeProviderProps;
|
||||
userProps?: TokenProps;
|
||||
tokenProps?: TokenProps;
|
||||
}
|
||||
|
||||
export function Providers({ children, themeProps, userProps }: ProvidersProps) {
|
||||
export function Providers({ children, themeProps, tokenProps }: ProvidersProps) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<NextUIProvider navigate={router.push}>
|
||||
<NextThemesProvider {...themeProps}>
|
||||
<TokenProvider {...userProps}>{children}</TokenProvider>
|
||||
<TokenProvider {...tokenProps}>{children}</TokenProvider>
|
||||
</NextThemesProvider>
|
||||
</NextUIProvider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user