-
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.
[recnet-web] Subscription setting UI (#350)
## Description <!--- Describe your changes in detail --> Finish subscription setting UI to select subscription type and channels. Misc: - Refactor code (split code) for UserSettingDialog - Add setting button in User Dropdown <img width="363" alt="Screenshot 2024-11-07 at 6 19 58 PM" src="https://github.com/user-attachments/assets/376b45de-9eff-4f23-9e32-d4532f9c62d9"> ## Related Issue <!--- This project only accepts pull requests related to open issues --> <!--- If suggesting a new feature or change, please discuss it in an issue first --> <!--- If fixing a bug, there should be an issue describing it with steps to reproduce --> <!--- Please link to the issue here: --> ## Notes <!-- Other thing to say --> ## Test <!--- Please describe in detail how you tested your changes locally. --> Open Setting Dialog and play with the subscription form - For weekly digest, should show error if trying to unsubscribe all channels - After save, verify changes in DB using `prisma:studio` or sql client ## Screenshots (if appropriate): <!--- Add screenshots of your changes here --> <img width="652" alt="Screenshot 2024-11-07 at 6 22 20 PM" src="https://github.com/user-attachments/assets/28628173-f325-4dae-b341-65d3c182e201"> ## TODO - [x] Clear `console.log` or `console.error` for debug usage - [x] Update the documentation `recnet-docs` if needed
- Loading branch information
Showing
13 changed files
with
799 additions
and
313 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
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
127 changes: 127 additions & 0 deletions
127
apps/recnet/src/components/setting/UserSettingDialog.tsx
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,127 @@ | ||
"use client"; | ||
|
||
import { | ||
PersonIcon, | ||
Cross1Icon, | ||
EnvelopeClosedIcon, | ||
} from "@radix-ui/react-icons"; | ||
import { Dialog, Button, Text } from "@radix-ui/themes"; | ||
import { Settings } from "lucide-react"; | ||
import React, { useMemo, useState, createContext, useContext } from "react"; | ||
|
||
import { useAuth } from "@recnet/recnet-web/app/AuthContext"; | ||
import { cn } from "@recnet/recnet-web/utils/cn"; | ||
|
||
import { AccountSetting } from "./account/AccountSetting"; | ||
import { ProfileEditForm } from "./profile/ProfileEditForm"; | ||
import { SubscriptionSetting } from "./subscription/SubscriptionSetting"; | ||
|
||
const tabs = { | ||
PROFILE: { | ||
label: "Profile", | ||
icon: <PersonIcon />, | ||
component: ProfileEditForm, | ||
}, | ||
ACCOUNT: { | ||
label: "Account", | ||
icon: <Settings className="w-[15px] h-[15px]" />, | ||
component: AccountSetting, | ||
}, | ||
SUBSCRIPTION: { | ||
label: "Subscription", | ||
icon: <EnvelopeClosedIcon />, | ||
component: SubscriptionSetting, | ||
}, | ||
} as const; | ||
type TabKey = keyof typeof tabs; | ||
|
||
const UserSettingDialogContext = createContext<{ | ||
open: boolean; | ||
setOpen: (open: boolean) => void; | ||
activeTab: TabKey; | ||
setActiveTab: (tab: TabKey) => void; | ||
} | null>(null); | ||
|
||
export function useUserSettingDialogContext() { | ||
const context = useContext(UserSettingDialogContext); | ||
if (!context) { | ||
throw new Error( | ||
"useUserSettingDialog must be used within a UserSettingDialogProvider" | ||
); | ||
} | ||
return context; | ||
} | ||
|
||
interface UserSettingDialogProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
export function UserSettingDialogProvider(props: UserSettingDialogProps) { | ||
const { children } = props; | ||
const { user } = useAuth(); | ||
const [open, setOpen] = useState(false); | ||
const [activeTab, setActiveTab] = useState<TabKey>("PROFILE"); | ||
|
||
const TabComponent = useMemo(() => tabs[activeTab].component, [activeTab]); | ||
|
||
if (!user) { | ||
return children; | ||
} | ||
|
||
return ( | ||
<UserSettingDialogContext.Provider | ||
value={{ | ||
open, | ||
setOpen, | ||
activeTab, | ||
setActiveTab, | ||
}} | ||
> | ||
<Dialog.Root open={open} onOpenChange={setOpen}> | ||
<Dialog.Content | ||
maxWidth={{ | ||
initial: "480px", | ||
md: "640px", | ||
}} | ||
className="relative" | ||
> | ||
<Dialog.Close className="absolute top-6 right-4 hidden md:block"> | ||
<Button variant="soft" color="gray" className="cursor-pointer"> | ||
<Cross1Icon /> | ||
</Button> | ||
</Dialog.Close> | ||
<div className="flex flex-row gap-x-8 md:p-4"> | ||
<div className="w-fit md:w-[25%] flex flex-col gap-y-2"> | ||
{Object.entries(tabs).map(([key, { label }]) => ( | ||
<div | ||
key={key} | ||
className={cn( | ||
"py-1 px-4 rounded-2 flex gap-x-2 items-center cursor-pointer hover:bg-gray-4", | ||
{ | ||
"bg-gray-5": key === activeTab, | ||
} | ||
)} | ||
onClick={() => setActiveTab(key as TabKey)} | ||
> | ||
{tabs[key as TabKey].icon} | ||
<Text | ||
size={{ | ||
initial: "1", | ||
md: "2", | ||
}} | ||
> | ||
{label} | ||
</Text> | ||
</div> | ||
))} | ||
</div> | ||
<div className="w-full h-[600px] md:h-[750px] overflow-y-auto"> | ||
<TabComponent /> | ||
</div> | ||
</div> | ||
</Dialog.Content> | ||
</Dialog.Root> | ||
{children} | ||
</UserSettingDialogContext.Provider> | ||
); | ||
} |
49 changes: 49 additions & 0 deletions
49
apps/recnet/src/components/setting/account/AccountSetting.tsx
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,49 @@ | ||
"use client"; | ||
|
||
import { Dialog, Button, Text } from "@radix-ui/themes"; | ||
import { useRouter } from "next/navigation"; | ||
|
||
import { trpc } from "@recnet/recnet-web/app/_trpc/client"; | ||
import { DoubleConfirmButton } from "@recnet/recnet-web/components/DoubleConfirmButton"; | ||
import { logout } from "@recnet/recnet-web/firebase/auth"; | ||
|
||
export function AccountSetting() { | ||
const deactivateMutation = trpc.deactivate.useMutation(); | ||
const router = useRouter(); | ||
|
||
return ( | ||
<div> | ||
<Dialog.Title>Account Setting</Dialog.Title> | ||
<Dialog.Description size="2" mb="4" className="text-gray-11"> | ||
Make changes to account settings. | ||
</Dialog.Description> | ||
|
||
<Text size="4" color="red" className="block"> | ||
Deactivate Account | ||
</Text> | ||
<Text size="1" className="text-gray-11 block"> | ||
{ | ||
"Your account will be deactivated and you will be logged out. You can reactivate your account by logging in again." | ||
} | ||
{ | ||
" While your account is deactivated, your profile will be hidden from other users. You will not receive any weekly digest emails." | ||
} | ||
</Text> | ||
<div className="flex flex-row w-full mt-4"> | ||
<DoubleConfirmButton | ||
onConfirm={async () => { | ||
await deactivateMutation.mutateAsync(); | ||
await logout(); | ||
router.replace("/"); | ||
}} | ||
title="Deactivate Account" | ||
description="Are you sure you want to deactivate your account?" | ||
> | ||
<Button color="red" className="bg-red-10 cursor-pointer"> | ||
Deactivate Account | ||
</Button> | ||
</DoubleConfirmButton> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.