-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 마이페이지 디자인 수정 및 설정 페이지 퍼블리싱 (#82)
* feat: 마이페이지 디자인 수정 및 추가 * feat: 설정 페이지 퍼블리싱 * feat: 로그아웃 Dialog
- Loading branch information
Showing
8 changed files
with
296 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import type { ReactNode } from "react"; | ||
|
||
export const Caption = ({ children }: { children: ReactNode }) => { | ||
return ( | ||
<div className="rounded-full w-fit px-[10px] py-[2px] bg-gradient-to-r from-main4-gradient-from to-main4-gradient-to"> | ||
{children} | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { Button } from "@repo/design-system/Button"; | ||
import { Dialog } from "@repo/design-system/Dialog"; | ||
import { MaxWidthBox } from "@repo/design-system/MaxWidthBox"; | ||
import { Text, textVariants } from "@repo/design-system/Text"; | ||
import { cn } from "@repo/design-system/cn"; | ||
import { Flex } from "@repo/ui/Flex"; | ||
import { JustifyBetween } from "@repo/ui/JustifyBetween"; | ||
import { Stack } from "@repo/ui/Stack"; | ||
import { overlay } from "overlay-kit"; | ||
import { useState } from "react"; | ||
import { openExternalUrl } from "~/shared/utils/openExternalUrl"; | ||
|
||
interface SettingMenuItemProps { | ||
type: "toggle" | "exit" | "link"; | ||
menuName: string; | ||
onClick?: () => void; | ||
link?: string; | ||
defaultValue?: boolean; | ||
} | ||
|
||
export const SettingMenuItem = ({ | ||
type, | ||
menuName, | ||
onClick, | ||
link, | ||
defaultValue, | ||
}: SettingMenuItemProps) => { | ||
const [isOn, setIsOn] = useState(defaultValue || false); | ||
|
||
const handleClick = () => { | ||
if (type === "toggle") { | ||
setIsOn(!isOn); | ||
} else if (type === "exit") { | ||
_LogoutOverlay.open(); | ||
} else if (type === "link" && link) { | ||
openExternalUrl(link); | ||
} | ||
}; | ||
|
||
return ( | ||
<Flex className="py-4 flex justify-between items-center cursor-pointer" onClick={handleClick}> | ||
<Text | ||
variant="body/16_sb" | ||
className={cn(type === "exit" ? "text-gray-400" : "text-gray-800")} | ||
> | ||
{menuName} | ||
</Text> | ||
{type === "toggle" && ( | ||
<button | ||
onClick={handleClick} | ||
className={cn( | ||
textVariants({ variant: "body/16_sb" }), | ||
isOn ? "text-green" : "text-gray-500", | ||
)} | ||
> | ||
{isOn ? "ON" : "OFF"} | ||
</button> | ||
)} | ||
</Flex> | ||
); | ||
}; | ||
|
||
const _LogoutOverlay = { | ||
open: () => { | ||
return overlay.open(({ isOpen, close, unmount }) => { | ||
return ( | ||
<LogoutDialog | ||
isOpen={isOpen} | ||
onOpenChange={() => { | ||
close(); | ||
setTimeout(unmount, 2000); | ||
}} | ||
/> | ||
); | ||
}); | ||
}, | ||
}; | ||
|
||
const LogoutDialog = (props: { | ||
isOpen?: boolean; | ||
onOpenChange?: (bool: boolean) => void; | ||
}) => { | ||
const { isOpen, onOpenChange } = props; | ||
return ( | ||
<Dialog.Root open={isOpen} onOpenChange={onOpenChange}> | ||
<Dialog.Portal> | ||
<Dialog.Overlay className="z-[6]" /> | ||
<Dialog.Content> | ||
<Dialog.Title className=" sr-only">로그아웃</Dialog.Title> | ||
<Dialog.Description className=" sr-only">로그아웃을 합니다.</Dialog.Description> | ||
<MaxWidthBox className="flex z-[7] justify-center items-center fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] px-6"> | ||
<Stack className=" bg-white rounded-[14px] pt-10 pb-4 px-4 justify-center items-center"> | ||
<Text className=" whitespace-pre-wrap text-gray-800" variant={"title/20_sb"}> | ||
정말 로그아웃할까요? | ||
</Text> | ||
<JustifyBetween className=" w-full mt-9 gap-2"> | ||
<Button | ||
size={"small"} | ||
className=" w-full rounded-[14px]" | ||
variant={"gray"} | ||
onClick={() => onOpenChange?.(false)} | ||
> | ||
아니요 | ||
</Button> | ||
<Button size={"small"} className=" w-full rounded-[14px]" variant={"warning"}> | ||
로그아웃 | ||
</Button> | ||
</JustifyBetween> | ||
</Stack> | ||
</MaxWidthBox> | ||
</Dialog.Content> | ||
</Dialog.Portal> | ||
</Dialog.Root> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { AspectRatio } from "@repo/design-system/AspectRatio"; | ||
import { Caption } from "@repo/design-system/Caption"; | ||
import { Image } from "@repo/design-system/Image"; | ||
import { Text } from "@repo/design-system/Text"; | ||
import { Flex } from "@repo/ui/Flex"; | ||
import { Stack } from "@repo/ui/Stack"; | ||
import { wrap } from "@suspensive/react"; | ||
import { useSuspenseQuery } from "@tanstack/react-query"; | ||
import { motion } from "motion/react"; | ||
import { useTestUserQueryOptions } from "~/entities/user/api/getTestUser"; | ||
import { ExpProgressBar } from "~/entities/user/components/ExpProgressBar"; | ||
import { calculateUserLevel, getExpPercentage, getGoalExp } from "~/entities/user/model/user.model"; | ||
|
||
const ExpSection = (props: { exp: number; goalExp: number; percentage: number; level: string }) => { | ||
const { exp, goalExp, percentage, level } = props; | ||
const formatExp = percentage.toFixed(2); | ||
return ( | ||
<Stack className=" w-full px-[20px]"> | ||
<Flex className=" gap-x-[6px] items-center"> | ||
<Text variant={"body/18_sb"} className=" text-nowrap text-gray-100"> | ||
{level} | ||
</Text> | ||
|
||
<ExpProgressBar value={percentage} totalExp={goalExp} currentExp={exp} /> | ||
<Text variant={"body/14_sb"} className="text-white-violet ml-[1px]"> | ||
{formatExp}% | ||
</Text> | ||
</Flex> | ||
</Stack> | ||
); | ||
}; | ||
|
||
const Fallback = () => { | ||
return ( | ||
<Stack className=" w-full bg-navy"> | ||
<motion.div | ||
className=" w-full h-full" | ||
initial={{ opacity: 0 }} | ||
animate={{ opacity: 1 }} | ||
transition={{ duration: 0.5, delay: 0.3 }} | ||
> | ||
<AspectRatio ratio={375 / 343} className=" flex justify-center items-center"> | ||
<Stack> | ||
<Stack> | ||
<Text>머큐리와 함께한 지 000일</Text> | ||
<Text></Text> | ||
</Stack> | ||
<Image src={HOME_ASSETS.HOME_MERCURY} alt="mercury character" objectfit={"fill"} /> | ||
<ExpSection exp={0} goalExp={0} percentage={0} level={`레벨 1`} /> | ||
</Stack> | ||
</AspectRatio> | ||
</motion.div> | ||
</Stack> | ||
); | ||
}; | ||
|
||
export const MainSection = wrap | ||
.Suspense({ | ||
fallback: <Fallback />, | ||
}) | ||
.on(() => { | ||
const { data: user } = useSuspenseQuery(useTestUserQueryOptions()); | ||
|
||
const nickname = `테스터${user.nickname.slice(10, 14)}`; | ||
|
||
const level = calculateUserLevel(user.exp); | ||
const goalExp = getGoalExp(level); | ||
const exp = user.exp + 50; | ||
const percentage = getExpPercentage(exp, goalExp); | ||
|
||
return ( | ||
<Stack className=" w-full bg-navy justify-between"> | ||
<motion.div | ||
className=" w-full h-full" | ||
initial={{ opacity: 0 }} | ||
animate={{ opacity: 1 }} | ||
transition={{ duration: 0.5, delay: 0.3 }} | ||
> | ||
<AspectRatio ratio={375 / 392} className=" flex justify-center items-center"> | ||
<Stack className="gap-[25px]"> | ||
<Stack className="px-5 gap-[6px]"> | ||
<Caption> | ||
<Text className="text-white" variant={"caption/12_m"}> | ||
머큐리와 함께한 지 000일 | ||
</Text> | ||
</Caption> | ||
<Text variant={"title/25_b"} className="text-gray-100"> | ||
{nickname} | ||
</Text> | ||
</Stack> | ||
|
||
<Image | ||
src={HOME_ASSETS.HOME_MERCURY} | ||
alt="mercury character" | ||
objectfit={"fill"} | ||
className="px-[36px]" | ||
/> | ||
|
||
<ExpSection | ||
exp={exp} | ||
goalExp={goalExp} | ||
percentage={percentage} | ||
level={`레벨 ${level}`} | ||
/> | ||
</Stack> | ||
</AspectRatio> | ||
</motion.div> | ||
</Stack> | ||
); | ||
}); | ||
|
||
const HOME_ASSETS = { | ||
HOME_MERCURY: "/images/home/home_mercury.webp", | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.