From bdc6de39b42e500be021d6f04d108a5eca97a0c8 Mon Sep 17 00:00:00 2001 From: Tania Gutierrez Date: Wed, 13 Mar 2024 21:52:31 -0400 Subject: [PATCH] feat: Added My Account route --- app/components/icons.tsx | 228 ++++++++++++++-------- app/components/management-card.tsx | 123 ++++++++++++ app/components/ui/button.tsx | 2 +- app/components/ui/dropdown-menu.tsx | 203 ++++++++++++++++++++ app/images/QR.png | Bin 0 -> 5012 bytes app/routes/account.tsx | 287 ++++++++++++++++++++++++++++ 6 files changed, 762 insertions(+), 81 deletions(-) create mode 100644 app/components/management-card.tsx create mode 100644 app/components/ui/dropdown-menu.tsx create mode 100644 app/images/QR.png create mode 100644 app/routes/account.tsx diff --git a/app/components/icons.tsx b/app/components/icons.tsx index 72fab8a..64dd2af 100644 --- a/app/components/icons.tsx +++ b/app/components/icons.tsx @@ -7,8 +7,7 @@ export const InfoIcon = ({ className }: { className?: string }) => { viewBox="0 0 23 24" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { - ) -} + ); +}; export const AddIcon = ({ className }: { className?: string }) => { return ( @@ -38,8 +37,7 @@ export const AddIcon = ({ className }: { className?: string }) => { viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { - ) -} + ); +}; export const CloudIcon = ({ className }: { className?: string }) => { return ( @@ -64,15 +62,14 @@ export const CloudIcon = ({ className }: { className?: string }) => { viewBox="0 0 23 21" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const CloudDownloadIcon = ({ className }: { className?: string }) => { return ( @@ -83,8 +80,7 @@ export const CloudDownloadIcon = ({ className }: { className?: string }) => { viewBox="0 0 21 15" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { fill="currentColor" /> - ) -} + ); +}; export const CloudUploadIcon = ({ className }: { className?: string }) => { return ( @@ -104,15 +100,14 @@ export const CloudUploadIcon = ({ className }: { className?: string }) => { viewBox="-0.5 0 21 17" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const CloudUploadSolidIcon = ({ className }: { className?: string }) => { return ( @@ -123,15 +118,14 @@ export const CloudUploadSolidIcon = ({ className }: { className?: string }) => { viewBox="0 0 24 16" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const CrownIcon = ({ className }: { className?: string }) => { return ( @@ -142,15 +136,14 @@ export const CrownIcon = ({ className }: { className?: string }) => { viewBox="0 0 20 15" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const PersonIcon = ({ className }: { className?: string }) => { return ( @@ -161,15 +154,14 @@ export const PersonIcon = ({ className }: { className?: string }) => { viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const CheckRoundedIcon = ({ className }: { className?: string }) => { return ( @@ -180,15 +172,14 @@ export const CheckRoundedIcon = ({ className }: { className?: string }) => { viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const ClockIcon = ({ className }: { className?: string }) => { return ( @@ -199,15 +190,14 @@ export const ClockIcon = ({ className }: { className?: string }) => { viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const CircleLockIcon = ({ className }: { className?: string }) => { return ( @@ -218,15 +208,14 @@ export const CircleLockIcon = ({ className }: { className?: string }) => { viewBox="0 0 23 24" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const DriveIcon = ({ className }: { className?: string }) => { return ( @@ -237,15 +226,14 @@ export const DriveIcon = ({ className }: { className?: string }) => { viewBox="0 0 23 24" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const PageIcon = ({ className }: { className?: string }) => { return ( @@ -256,8 +244,7 @@ export const PageIcon = ({ className }: { className?: string }) => { viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { strokeLinejoin="round" /> - ) -} + ); +}; export const TrashIcon = ({ className }: { className?: string }) => { return ( @@ -307,8 +294,7 @@ export const TrashIcon = ({ className }: { className?: string }) => { viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { fill="currentColor" /> - ) -} + ); +}; export const CloudCheckIcon = ({ className }: { className?: string }) => { return ( @@ -346,8 +332,7 @@ export const CloudCheckIcon = ({ className }: { className?: string }) => { viewBox="0 0 72 48" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { fill="currentColor" /> - ) -} + ); +}; export const BoxCheckedIcon = ({ className }: { className?: string }) => { return ( @@ -367,8 +352,7 @@ export const BoxCheckedIcon = ({ className }: { className?: string }) => { viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { strokeLinejoin="round" /> - ) -} + ); +}; export const PictureIcon = ({ className }: { className?: string }) => { return ( @@ -396,8 +380,7 @@ export const PictureIcon = ({ className }: { className?: string }) => { viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { fill="currentColor" /> - ) -} + ); +}; export const XlsxIcon = ({ className }: { className?: string }) => { return ( @@ -417,8 +400,7 @@ export const XlsxIcon = ({ className }: { className?: string }) => { viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { fill="currentColor" /> - ) -} + ); +}; export const FileIcon = ({ className }: { className?: string }) => { return ( @@ -438,15 +420,14 @@ export const FileIcon = ({ className }: { className?: string }) => { viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> - ) -} + ); +}; export const MoreIcon = ({ className }: { className?: string }) => { return ( @@ -457,8 +438,7 @@ export const MoreIcon = ({ className }: { className?: string }) => { viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" - className={className} - > + className={className}> { fill="currentColor" /> - ) -} + ); +}; + +export const FingerPrintIcon = ({ className }: { className?: string }) => { + return ( + + + + + + + + + + + ); +}; + +export const EditIcon = ({ className }: { className?: string }) => { + return ( + + + + + + + + + + + ); +}; + +export const ThemeIcon = ({ className }: { className?: string }) => { + return ( + + + + ); +}; + +export const ChevronDownIcon = ({ className }: { className?: string }) => { + return ( + + + + ); +}; diff --git a/app/components/management-card.tsx b/app/components/management-card.tsx new file mode 100644 index 0000000..8cb69b5 --- /dev/null +++ b/app/components/management-card.tsx @@ -0,0 +1,123 @@ +import { cn } from "~/utils"; +import { Avatar } from "./ui/avatar"; +import { Button } from "./ui/button"; +import { AddIcon, EditIcon, FingerPrintIcon } from "./icons"; +import { Dialog, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog"; +import { DialogContent, Portal } from "@radix-ui/react-dialog"; + +interface ManagementCardProps { + title?: string; + value?: string; + subtitle?: string; + isInviteCard?: boolean; + isPasswordCard?: boolean; + isAvatarCard?: boolean; + isDeleteCard?: boolean + buttonText?: string; + buttonOnClick?: () => void + dialogNode?: React.ReactNode +} + +export const ManagementCard = ({ + title, + isAvatarCard, + isInviteCard, + isPasswordCard, + isDeleteCard, + subtitle, + value, + buttonText, + buttonOnClick, + dialogNode +}: ManagementCardProps) => { + const buttonVariant: string = isInviteCard ? "accent" : isDeleteCard ? "destructive" : "default"; + return ( +
+ {isAvatarCard ? ( +
+ + +
+ ) : ( + <> +
+ +

{title}

+
+ {subtitle && ( + {subtitle} + )} + {value && ( + {value} + )} + {isPasswordCard && } + {!dialogNode ? ( + + ): ( + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your account + and remove your data from our servers. + + + + + + )} + + )} +
+ ); +}; + +const PasswordDots = ({ className }: { className?: string }) => { + return ( + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/app/components/ui/button.tsx b/app/components/ui/button.tsx index 6302846..6c8859e 100644 --- a/app/components/ui/button.tsx +++ b/app/components/ui/button.tsx @@ -14,7 +14,7 @@ const buttonVariants = cva( // TODO: name it better accent: "bg-ring text-primary-1-foreground hover:bg-ring/75 font-bold", destructive: - "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + "bg-destructive text-white shadow-sm hover:bg-destructive/90", outline: "border border-input bg-background shadow-sm hover:bg-primary-2/5", secondary: diff --git a/app/components/ui/dropdown-menu.tsx b/app/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..cbe1985 --- /dev/null +++ b/app/components/ui/dropdown-menu.tsx @@ -0,0 +1,203 @@ +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { + CheckIcon, + ChevronRightIcon, + DotFilledIcon, +} from "@radix-ui/react-icons" + +import { cn } from "~/utils" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/app/images/QR.png b/app/images/QR.png new file mode 100644 index 0000000000000000000000000000000000000000..2a2a4f61f1a38cb1f05c3ae9135652e96061d1b2 GIT binary patch literal 5012 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 nA +

My Account

+ } + button={ + + } + /> +

Account Management

+
+ + setModal({ ...openModal, changeEmail: true })} + /> + +
+

Security

+
+ setModal({ ...openModal, changePassword: true })} + /> + setModal({ ...openModal, setupTwoFactor: true })} + /> + +
+

More

+
+ + + +
+ {/* Dialogs must be near to body as possible to open the modal, otherwise will be restricted to parent height-width */} + + setModal({ ...openModal, changeEmail: value }) + } + currentValue="bsimpson@springfield.oh.gov.com" + /> + + setModal({ ...openModal, changePassword: value }) + } + /> + + setModal({ ...openModal, setupTwoFactor: value }) + } + /> + + ); +} + +const ChangeEmailSchema = z.object({ + email: z.string().email(), + password: z.string(), + retypePassword: z.string(), +}); + +const ChangeEmailForm = ({ + open, + setOpen, + currentValue, +}: { + open: boolean; + setOpen: (value: boolean) => void; + currentValue: string; +}) => { + const [form, fields] = useForm({ + id: "login", + constraint: getZodConstraint(ChangeEmailSchema), + onValidate({ formData }) { + return parseWithZod(formData, { schema: ChangeEmailSchema }); + }, + shouldValidate: "onSubmit", + }); + + return ( + + + + Change Email +
+ {currentValue} +
+
+ + + + + +
+
+
+ ); +}; + +const ChangePasswordSchema = z.object({ + currentPassword: z.string().email(), + newPassword: z.string(), + retypePassword: z.string(), +}); + +const ChangePasswordForm = ({ + open, + setOpen, +}: { + open: boolean; + setOpen: (value: boolean) => void; +}) => { + const [form, fields] = useForm({ + id: "login", + constraint: getZodConstraint(ChangeEmailSchema), + onValidate({ formData }) { + return parseWithZod(formData, { schema: ChangePasswordSchema }); + }, + shouldValidate: "onSubmit", + }); + + return ( + + + + Change Password +
+ + + + + +
+
+
+ ); +}; + +const SetupTwoFactorDialog = ({ + open, + setOpen, +}: { + open: boolean; + setOpen: (value: boolean) => void; +}) => { + const [continueModal, setContinue] = useState(false); + + return ( + { + setOpen(value) + setContinue(false); + }}> + + + Setup Two-Factor +
+ {continueModal ? ( + <> +

Enter the authentication code generated in your two-factor application to confirm your setup.

+ + + + ) : ( + <> +
+ QR +
+

+ Don’t have access to scan? Use this code instead. +

+
+ HHH7MFGAMPJ44OM44FGAMPJ44O232 +
+ + + )} +
+
+
+
+ ); +};