Compare commits
2 Commits
4432c4e7f6
...
f67ebbd98a
Author | SHA1 | Date |
---|---|---|
Tania Gutierrez | f67ebbd98a | |
Tania Gutierrez | ad033614f9 |
|
@ -477,9 +477,9 @@ export const EditIcon = ({ className }: { className?: string }) => {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
width="16"
|
width="13"
|
||||||
height="16"
|
height="13"
|
||||||
viewBox="0 0 16 16"
|
viewBox="0 0 13 13"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className={className}>
|
className={className}>
|
||||||
|
|
|
@ -1,123 +1,73 @@
|
||||||
import { cn } from "~/utils";
|
import { cn } from "~/utils";
|
||||||
import { Avatar } from "./ui/avatar";
|
import { Avatar } from "./ui/avatar";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { AddIcon, EditIcon, FingerPrintIcon } from "./icons";
|
import { EditIcon, FingerPrintIcon } from "./icons";
|
||||||
import { Dialog, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog";
|
|
||||||
import { DialogContent, Portal } from "@radix-ui/react-dialog";
|
|
||||||
|
|
||||||
interface ManagementCardProps {
|
const ManagementCardAvatar = ({ src }: { src?: string }) => {
|
||||||
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 (
|
return (
|
||||||
<div
|
<div className="flex justify-center">
|
||||||
className={cn(
|
|
||||||
"rounded-lg p-8 border w-full",
|
|
||||||
isInviteCard && "border-ring",
|
|
||||||
isAvatarCard && "flex justify-center items-center"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{isAvatarCard ? (
|
|
||||||
<div className="relative w-fit h-fit">
|
<div className="relative w-fit h-fit">
|
||||||
<Avatar className="border-2 border-ring h-28 w-28" />
|
<Avatar className="border-2 border-ring h-28 w-28" />
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="absolute bottom-0 right-0 z-50 flex items-center w-10 h-10 p-0 border-white rounded-full justiyf-center hover:bg-secondary-2"
|
className="absolute bottom-0 right-0 z-50 flex items-center w-10 h-10 p-0 border-white rounded-full justiyf-center hover:bg-secondary-2">
|
||||||
>
|
<EditIcon />
|
||||||
<EditIcon className="mt-1 ml-1" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div className="flex items-center gap-x-2">
|
|
||||||
<FingerPrintIcon className="text-ring" />
|
|
||||||
<h4 className="font-bold">{title}</h4>
|
|
||||||
</div>
|
|
||||||
{subtitle && (
|
|
||||||
<span className="block mt-4 mb-8 text-sm text-primary-2">{subtitle}</span>
|
|
||||||
)}
|
|
||||||
{value && (
|
|
||||||
<span className="block mt-4 mb-8 text-sm font-bold text-ring">{value}</span>
|
|
||||||
)}
|
|
||||||
{isPasswordCard && <PasswordDots className="mt-6 mb-8 text-primary-2" />}
|
|
||||||
{!dialogNode ? (
|
|
||||||
<Button
|
|
||||||
onClick={buttonOnClick}
|
|
||||||
className={`h-12 gap-x-2`}
|
|
||||||
variant={buttonVariant}
|
|
||||||
>
|
|
||||||
<AddIcon />
|
|
||||||
{buttonText}
|
|
||||||
</Button>
|
|
||||||
): (
|
|
||||||
<Dialog>
|
|
||||||
<DialogTrigger>Open</DialogTrigger>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
This action cannot be undone. This will permanently delete your account
|
|
||||||
and remove your data from our servers.
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const PasswordDots = ({ className }: { className?: string }) => {
|
const ManagementCardTitle = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}: React.PropsWithChildren<{ className?: string }>) => {
|
||||||
return (
|
return (
|
||||||
<svg
|
<div className={cn("flex items-center gap-x-2 font-semibold", className)}>
|
||||||
width="219"
|
<FingerPrintIcon className="text-ring" />
|
||||||
height="7"
|
{children}
|
||||||
viewBox="0 0 219 7"
|
</div>
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className={className}
|
|
||||||
>
|
|
||||||
<circle cx="3.7771" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="31.7771" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="45.7771" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="17.7771" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="59.7771" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="73.7771" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="87.7771" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="101.777" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="131.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="117.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="145.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="159.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="173.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="187.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="201.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
<circle cx="215.5" cy="3.5" r="3.5" fill="currentColor" />
|
|
||||||
</svg>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ManagementCardContent = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}: React.PropsWithChildren<{ className?: string }>) => {
|
||||||
|
return (
|
||||||
|
<div className={cn("mt-4 mb-8 text-sm text-primary-2", className)}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ManagementCardFooter = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}: React.PropsWithChildren<{ className?: string }>) => {
|
||||||
|
return <div className={className}>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ManagementCard = ({
|
||||||
|
children,
|
||||||
|
variant,
|
||||||
|
}: React.PropsWithChildren<{ variant?: string }>) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"rounded-lg p-8 border w-full border-[--variant-color]",
|
||||||
|
!variant && "[--variant-color:theme(colors.border)]",
|
||||||
|
variant === "accent" && "[--variant-color:theme(colors.primary-1.DEFAULT)]",
|
||||||
|
)}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
ManagementCard,
|
||||||
|
ManagementCardAvatar,
|
||||||
|
ManagementCardContent,
|
||||||
|
ManagementCardFooter,
|
||||||
|
ManagementCardTitle,
|
||||||
|
};
|
|
@ -4,8 +4,8 @@ import { useState } from "react";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Field } from "~/components/forms";
|
import { Field } from "~/components/forms";
|
||||||
import { GeneralLayout } from "~/components/general-layout";
|
import { GeneralLayout } from "~/components/general-layout";
|
||||||
import { AddIcon, CloudIcon } from "~/components/icons";
|
import { AddIcon, CloudIcon, CrownIcon } from "~/components/icons";
|
||||||
import { ManagementCard } from "~/components/management-card";
|
import { ManagementCard, ManagementCardAvatar, ManagementCardContent, ManagementCardFooter, ManagementCardTitle } from "~/components/management-card";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
@ -47,58 +47,106 @@ export default function MyAccount() {
|
||||||
/>
|
/>
|
||||||
<h2 className="font-bold my-8">Account Management</h2>
|
<h2 className="font-bold my-8">Account Management</h2>
|
||||||
<div className="grid grid-cols-3 gap-x-8">
|
<div className="grid grid-cols-3 gap-x-8">
|
||||||
<ManagementCard isAvatarCard />
|
<ManagementCard>
|
||||||
<ManagementCard
|
<ManagementCardAvatar />
|
||||||
title="Email Address"
|
</ManagementCard>
|
||||||
value="bsimpson@springfield.oh.gov.com"
|
<ManagementCard>
|
||||||
buttonText="Change Email Address"
|
<ManagementCardTitle>Email Address</ManagementCardTitle>
|
||||||
buttonOnClick={() => setModal({ ...openModal, changeEmail: true })}
|
<ManagementCardContent className="text-ring font-semibold">
|
||||||
/>
|
bsimpson@springfield.oh.gov.com
|
||||||
<ManagementCard
|
</ManagementCardContent>
|
||||||
title="Account Type"
|
<ManagementCardFooter>
|
||||||
value="Lite Premium Account"
|
<Button className="h-12 gap-x-2" onClick={() => setModal({ ...openModal, changeEmail: true })}>
|
||||||
buttonText="Upgrade to Premium"
|
<AddIcon />
|
||||||
/>
|
Change Email Address
|
||||||
|
</Button>
|
||||||
|
</ManagementCardFooter>
|
||||||
|
</ManagementCard>
|
||||||
|
<ManagementCard>
|
||||||
|
<ManagementCardTitle>Account Type</ManagementCardTitle>
|
||||||
|
<ManagementCardContent className="text-ring font-semibold flex gap-x-2">
|
||||||
|
Lite Premium Account
|
||||||
|
<CrownIcon />
|
||||||
|
</ManagementCardContent>
|
||||||
|
<ManagementCardFooter>
|
||||||
|
<Button className="h-12 gap-x-2">
|
||||||
|
<AddIcon />
|
||||||
|
Upgrade to Premium
|
||||||
|
</Button>
|
||||||
|
</ManagementCardFooter>
|
||||||
|
</ManagementCard>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="font-bold my-8">Security</h2>
|
<h2 className="font-bold my-8">Security</h2>
|
||||||
<div className="grid grid-cols-3 gap-x-8">
|
<div className="grid grid-cols-3 gap-x-8">
|
||||||
<ManagementCard
|
<ManagementCard>
|
||||||
isPasswordCard
|
<ManagementCardTitle>Password</ManagementCardTitle>
|
||||||
title="Password"
|
<ManagementCardContent>
|
||||||
buttonText="Change Password"
|
<PasswordDots className="mt-6" />
|
||||||
buttonOnClick={() => setModal({ ...openModal, changePassword: true })}
|
</ManagementCardContent>
|
||||||
/>
|
<ManagementCardFooter>
|
||||||
<ManagementCard
|
<Button className="h-12 gap-x-2" onClick={() => setModal({ ...openModal, changePassword: true })}>
|
||||||
title="Two-Factor Authentication"
|
<AddIcon />
|
||||||
subtitle="Improve security by enabling 2FA."
|
Change Password
|
||||||
buttonText="Enable Two-Factor Authorization"
|
</Button>
|
||||||
buttonOnClick={() => setModal({ ...openModal, setupTwoFactor: true })}
|
</ManagementCardFooter>
|
||||||
/>
|
</ManagementCard>
|
||||||
<ManagementCard
|
<ManagementCard>
|
||||||
title="Backup Key"
|
<ManagementCardTitle>Two-Factor Authentication</ManagementCardTitle>
|
||||||
subtitle="Never share this code with anyone."
|
<ManagementCardContent>
|
||||||
buttonText="Export Backup Key"
|
Improve security by enabling 2FA.
|
||||||
/>
|
</ManagementCardContent>
|
||||||
|
<ManagementCardFooter>
|
||||||
|
<Button className="h-12 gap-x-2" onClick={() => setModal({ ...openModal, setupTwoFactor: true })}>
|
||||||
|
<AddIcon />
|
||||||
|
Enable Two-Factor Authorization
|
||||||
|
</Button>
|
||||||
|
</ManagementCardFooter>
|
||||||
|
</ManagementCard>
|
||||||
|
<ManagementCard>
|
||||||
|
<ManagementCardTitle>Backup Key</ManagementCardTitle>
|
||||||
|
<ManagementCardContent>
|
||||||
|
Never share this code with anyone.
|
||||||
|
</ManagementCardContent>
|
||||||
|
<ManagementCardFooter>
|
||||||
|
<Button className="h-12 gap-x-2">
|
||||||
|
<AddIcon />
|
||||||
|
Export Backup Key
|
||||||
|
</Button>
|
||||||
|
</ManagementCardFooter>
|
||||||
|
</ManagementCard>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="font-bold my-8">More</h2>
|
<h2 className="font-bold my-8">More</h2>
|
||||||
<div className="grid grid-cols-3 gap-x-8">
|
<div className="grid grid-cols-3 gap-x-8">
|
||||||
<ManagementCard
|
<ManagementCard variant="accent">
|
||||||
isInviteCard
|
<ManagementCardTitle>Invite a Friend</ManagementCardTitle>
|
||||||
title="Invite a Friend"
|
<ManagementCardContent>Get 1 GB per friend invited for free (max 5 GB).</ManagementCardContent>
|
||||||
subtitle="Get 1 GB per friend invited for free (max 5 GB)."
|
<ManagementCardFooter>
|
||||||
buttonText="Send Invitation"
|
<Button variant="accent" className="h-12 gap-x-2">
|
||||||
/>
|
<AddIcon />
|
||||||
<ManagementCard
|
Send Invitation
|
||||||
title="Read our Resources"
|
</Button>
|
||||||
subtitle="Navigate helpful articles or get assistance."
|
</ManagementCardFooter>
|
||||||
buttonText="Open Support Centre"
|
</ManagementCard>
|
||||||
/>
|
<ManagementCard>
|
||||||
<ManagementCard
|
<ManagementCardTitle>Read our Resources</ManagementCardTitle>
|
||||||
isDeleteCard
|
<ManagementCardContent>Navigate helpful articles or get assistance.</ManagementCardContent>
|
||||||
title="Delete Account"
|
<ManagementCardFooter>
|
||||||
subtitle="Once initiated, this action cannot be undone."
|
<Button className="h-12 gap-x-2">
|
||||||
buttonText="Delete my Account"
|
<AddIcon />
|
||||||
/>
|
Open Support Centre
|
||||||
|
</Button>
|
||||||
|
</ManagementCardFooter>
|
||||||
|
</ManagementCard>
|
||||||
|
<ManagementCard>
|
||||||
|
<ManagementCardTitle>Delete Account</ManagementCardTitle>
|
||||||
|
<ManagementCardContent>Once initiated, this action cannot be undone.</ManagementCardContent>
|
||||||
|
<ManagementCardFooter>
|
||||||
|
<Button className="h-12 gap-x-2" variant="destructive">
|
||||||
|
<AddIcon />
|
||||||
|
Delete my Account
|
||||||
|
</Button>
|
||||||
|
</ManagementCardFooter>
|
||||||
|
</ManagementCard>
|
||||||
</div>
|
</div>
|
||||||
{/* Dialogs must be near to body as possible to open the modal, otherwise will be restricted to parent height-width */}
|
{/* Dialogs must be near to body as possible to open the modal, otherwise will be restricted to parent height-width */}
|
||||||
<ChangeEmailForm
|
<ChangeEmailForm
|
||||||
|
@ -294,3 +342,32 @@ const SetupTwoFactorDialog = ({
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PasswordDots = ({ className }: { className?: string }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="219"
|
||||||
|
height="7"
|
||||||
|
viewBox="0 0 219 7"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className={className}>
|
||||||
|
<circle cx="3.7771" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="31.7771" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="45.7771" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="17.7771" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="59.7771" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="73.7771" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="87.7771" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="101.777" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="131.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="117.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="145.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="159.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="173.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="187.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="201.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
<circle cx="215.5" cy="3.5" r="3.5" fill="currentColor" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue