Skip to content

Commit

Permalink
Dynamic dialogs based on selections (Codehagen#185)
Browse files Browse the repository at this point in the history
* feat(www): Implement the single modal structure in the codebase.

* feat(www): Develop the logic for dynamically displaying form inputs based on Account Type.

* feat(www): Integrate animations for transitioning between form steps.
  • Loading branch information
ousszizou authored Mar 4, 2024
1 parent 86bc586 commit 7909fd8
Show file tree
Hide file tree
Showing 19 changed files with 819 additions and 123 deletions.
128 changes: 15 additions & 113 deletions apps/www/components/buttons/AddAssetButton.tsx
Original file line number Diff line number Diff line change
@@ -1,123 +1,25 @@
import {
Bitcoin,
Building,
Car,
Folder,
GitGraph,
Hourglass,
MoreHorizontal,
Wallet,
} from "lucide-react";
import type { FC, ReactNode } from "react";

import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "../ui/button";
import { Dialog, DialogContent, DialogTrigger } from "../ui/dialog";

import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
interface FlowModalProps {
triggerLabel: string;
children: ReactNode;
}

export function AddAssetButton() {
export const AddAssetButton: FC<FlowModalProps> = ({
triggerLabel,
children,
}) => {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Add account</Button>
<Button variant="outline">{triggerLabel}</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Add new account</DialogTitle>
<DialogDescription>Add the account type you want.</DialogDescription>
</DialogHeader>
<RadioGroup
defaultValue="realestate"
className="mb-4 grid grid-cols-3 gap-4"
>
<div>
<RadioGroupItem
value="realestate"
id="realestate"
className="peer sr-only"
/>
<Label
htmlFor="realestate"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-checked:border-primary"
>
<Building className="mb-3 h-6 w-6" />
Real estate
</Label>
</div>
<div>
<RadioGroupItem
value="paypal"
id="paypal"
className="peer sr-only"
/>
<Label
htmlFor="paypal"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-checked:border-primary"
>
<GitGraph className="mb-3 h-6 w-6" />
Investment
</Label>
</div>
<div>
<RadioGroupItem value="apple" id="apple" className="peer sr-only" />
<Label
htmlFor="apple"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-checked:border-primary"
>
<Folder className="mb-3 h-6 w-6" />
Input
</Label>
</div>
</RadioGroup>
<RadioGroup defaultValue="crypto" className="grid grid-cols-3 gap-4">
<div>
<RadioGroupItem
value="crypto"
id="crypto"
className="peer sr-only"
/>
<Label
htmlFor="crypto"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-checked:border-primary"
>
<Wallet className="mb-3 h-6 w-6" />
Crypto
</Label>
</div>
<div>
<RadioGroupItem value="car" id="car" className="peer sr-only" />
<Label
htmlFor="car"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-checked:border-primary"
>
<Car className="mb-3 h-6 w-6" />
Car
</Label>
</div>
<div>
<RadioGroupItem value="misc" id="misc" className="peer sr-only" />
<Label
htmlFor="misc"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-checked:border-primary"
>
<MoreHorizontal className="mb-3 h-6 w-6" />
Misc
</Label>
</div>
</RadioGroup>
{/* <DialogFooter>
<Button type="submit">Save changes</Button>
</DialogFooter> */}
<DialogContent className="sm:max-w-[425px]" showCloseButton={false}>
{children}
</DialogContent>
</Dialog>
);
}
};
12 changes: 12 additions & 0 deletions apps/www/components/forms/account-form/car-fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useFormContext } from "react-hook-form";

import { CommonAccountFields } from "./common-account-fields";

export const CarFormFields = () => {
const { control } = useFormContext();
return (
<>
<CommonAccountFields />
</>
);
};
98 changes: 98 additions & 0 deletions apps/www/components/forms/account-form/common-account-fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import { useFormContext } from "react-hook-form";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
FormControl,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";

export const CommonAccountFields = () => {
const { control } = useFormContext();
return (
<>
{/* Purchase Date Field */}
<div className="grid gap-2">
<FormField
control={control}
name="purchaseDate"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Purchase Date</FormLabel>
<FormControl>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant={"outline"}
className={cn(
"justify-start text-left font-normal",
!field.value && "text-muted-foreground",
)}
>
{field.value ? (
format(field.value, "PPP")
) : (
<span>Pick a date</span>
)}
<CalendarIcon className="ml-2 h-4 w-4" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={field.value}
onSelect={field.onChange}
disabled={(date) =>
date > new Date() || date < new Date("1900-01-01")
}
initialFocus
/>
</PopoverContent>
</Popover>
</FormControl>
</FormItem>
)}
/>
</div>
{/* Purchase Value Field */}
<FormField
control={control}
name="purchaseValue"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Purchase Value</FormLabel>
<FormControl>
<Input {...field} placeholder="Purchase Value..." />
</FormControl>
</FormItem>
)}
/>
{/* Current Value Field */}
<FormField
control={control}
name="currentValue"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Current Value</FormLabel>
<FormControl>
<Input {...field} placeholder="Current Value..." />
</FormControl>
</FormItem>
)}
/>
</>
);
};
80 changes: 80 additions & 0 deletions apps/www/components/forms/account-form/crypto-fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useFormContext } from "react-hook-form";

import {
FormControl,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";

import { CommonAccountFields } from "./common-account-fields";

export const CryptoFormFields = () => {
const { control } = useFormContext();
return (
<>
{/* Currency Name Field */}
<div className="grid gap-2">
<FormField
control={control}
name="currencyName"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Currency Name</FormLabel>
<FormControl>
<Input {...field} placeholder="Currency Name..." />
</FormControl>
</FormItem>
)}
/>
</div>
{/* Wallet Address */}
<div className="grid gap-2">
<FormField
control={control}
name="walletAddress"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Wallet Address</FormLabel>
<FormControl>
<Input {...field} placeholder="Wallet Address..." />
</FormControl>
</FormItem>
)}
/>
</div>
{/* Conversion Rate (at Purchase) */}
<div className="grid gap-2">
<FormField
control={control}
name="conversionRate"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Conversion Rate</FormLabel>
<FormControl>
<Input {...field} placeholder="Conversion Rate..." />
</FormControl>
</FormItem>
)}
/>
</div>
{/* Current Conversion Rate */}
<div className="grid gap-2">
<FormField
control={control}
name="currentConversionRate"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Current Conversion Rate</FormLabel>
<FormControl>
<Input {...field} placeholder="Current Conversion Rate..." />
</FormControl>
</FormItem>
)}
/>
</div>
<CommonAccountFields />
</>
);
};
45 changes: 45 additions & 0 deletions apps/www/components/forms/account-form/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { type FC } from "react";
import { type UseFormReturn } from "react-hook-form";

import { type FormFields } from "@/hooks/use-flow-modal-state";
import { Form } from "@/components/ui/form";
import { type AccountType } from "@/components/modals/add-asset-flow";

import { CarFormFields } from "./car-fields";
import { CryptoFormFields } from "./crypto-fields";
import { InputFormFields } from "./input-fields";
import { InvestmentFormFields } from "./investment-fields";
import { MiscFormFields } from "./misc-fields";
import { RealEstateFormFields } from "./real-estate-fields";

const generateFormFields = (accountType: AccountType) => {
switch (accountType) {
case "real-estate":
return <RealEstateFormFields />;
case "crypto":
return <CryptoFormFields />;
case "investment":
return <InvestmentFormFields />;
case "input":
return <InputFormFields />;
case "car":
return <CarFormFields />;
case "misc":
return <MiscFormFields />;
default:
return null;
}
};

interface AccountFormProps {
type: AccountType;
form: UseFormReturn<FormFields>;
}

export const AccountForm: FC<AccountFormProps> = ({ type, form }) => {
return (
<Form {...form}>
<form className="space-y-3">{generateFormFields(type)}</form>
</Form>
);
};
12 changes: 12 additions & 0 deletions apps/www/components/forms/account-form/input-fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useFormContext } from "react-hook-form";

import { CommonAccountFields } from "./common-account-fields";

export const InputFormFields = () => {
const { control } = useFormContext();
return (
<>
<CommonAccountFields />
</>
);
};
Loading

0 comments on commit 7909fd8

Please sign in to comment.