Skip to content

Commit

Permalink
Merge pull request #367 from captableinc/feat/mask-input
Browse files Browse the repository at this point in the history
feat: mask numeric inputs
  • Loading branch information
dahal authored May 31, 2024
2 parents 528e10c + 4f8ed43 commit 111bcc6
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 63 deletions.
2 changes: 1 addition & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ model Safe {
status SafeStatusEnum @default(DRAFT)
capital Float // Amount of money invested
safeTemplate SafeTemplateEnum?
safeId String?
safeId String?
valuationCap Float?
discountRate Float?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { ShareClassMutationType } from "@/trpc/routers/share-class/schema";
import { zodResolver } from "@hookform/resolvers/zod";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { NumericFormat } from "react-number-format";
import { toast } from "sonner";

import {
Expand Down Expand Up @@ -128,19 +129,28 @@ const EquityPlanForm = ({
<FormField
control={form.control}
name="initialSharesReserved"
render={({ field }) => (
<FormItem>
<FormLabel>Initial reserved shares</FormLabel>
<FormControl>
<Input
type="number"
{...field}
value={parseBigInt(field.value)}
/>
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
)}
render={({ field }) => {
const { onChange, ...rest } = field;
return (
<FormItem>
<FormLabel>Initial reserved shares</FormLabel>
<FormControl>
<NumericFormat
thousandSeparator
allowedDecimalSeparators={["%"]}
decimalScale={2}
{...rest}
customInput={Input}
onValueChange={(values) => {
const { floatValue } = values;
onChange(floatValue);
}}
/>
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
);
}}
/>
</div>

Expand Down
49 changes: 38 additions & 11 deletions src/components/safe/steps/general-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import {
import { useFormValueUpdater } from "@/providers/form-value-provider";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { NumericFormat } from "react-number-format";
import { z } from "zod";

const formSchema = z.object({
safeId: z.string().min(1),
valuationCap: z.coerce.number(),
discountRate: z.coerce.number().optional(),
proRata: z.boolean(),
proRata: z.boolean().default(false).optional(),
});

export type TFormSchema = z.infer<typeof formSchema>;
Expand Down Expand Up @@ -71,11 +72,23 @@ export const GeneralDetails = () => {
control={form.control}
name="valuationCap"
render={({ field }) => {
const { onChange, ...rest } = field;
return (
<FormItem>
<FormLabel>Valuation cap</FormLabel>
<FormControl>
<Input type="number" {...field} />
<NumericFormat
thousandSeparator
allowedDecimalSeparators={["%"]}
decimalScale={2}
prefix={"$ "}
{...rest}
customInput={Input}
onValueChange={(values) => {
const { floatValue } = values;
onChange(floatValue);
}}
/>
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
Expand All @@ -86,15 +99,29 @@ export const GeneralDetails = () => {
<FormField
control={form.control}
name="discountRate"
render={({ field }) => (
<FormItem>
<FormLabel>Discount rate (optional)</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
)}
render={({ field }) => {
const { onChange, ...rest } = field;
return (
<FormItem>
<FormLabel>Discount rate (optional)</FormLabel>
<FormControl>
<NumericFormat
thousandSeparator
allowedDecimalSeparators={["%"]}
decimalScale={2}
suffix={" %"}
{...rest}
customInput={Input}
onValueChange={(values) => {
const { floatValue } = values;
onChange(floatValue);
}}
/>
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
);
}}
/>

<FormField
Expand Down
33 changes: 24 additions & 9 deletions src/components/safe/steps/investor-details/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { RiAddCircleLine } from "@remixicon/react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useForm, useFormContext, useWatch } from "react-hook-form";
import { NumericFormat } from "react-number-format";
import { z } from "zod";

const formSchema = z.object({
Expand Down Expand Up @@ -78,15 +79,29 @@ export function InvestorDetailsForm({ stakeholders }: InvestorsDetailsProps) {
<FormField
control={form.control}
name="capital"
render={({ field }) => (
<FormItem>
<FormLabel>Capital</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
)}
render={({ field }) => {
const { onChange, ...rest } = field;
return (
<FormItem>
<FormLabel>Capital</FormLabel>
<FormControl>
<NumericFormat
thousandSeparator
allowedDecimalSeparators={["%"]}
decimalScale={2}
prefix={"$ "}
{...rest}
customInput={Input}
onValueChange={(values) => {
const { floatValue } = values;
onChange(floatValue);
}}
/>
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
);
}}
/>
<FormField
control={form.control}
Expand Down
32 changes: 23 additions & 9 deletions src/components/securities/options/steps/general-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { OptionStatusEnum, OptionTypeEnum } from "@/prisma/enums";
import { useStockOptionFormValues } from "@/providers/stock-option-form-provider";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { NumericFormat } from "react-number-format";
import { z } from "zod";

const STATUSES = Object.values(OptionStatusEnum).map((val) => ({
Expand Down Expand Up @@ -106,15 +107,28 @@ export const GeneralDetails = () => {
<FormField
control={form.control}
name="quantity"
render={({ field }) => (
<FormItem>
<FormLabel>Quantity</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
)}
render={({ field }) => {
const { onChange, ...rest } = field;
return (
<FormItem>
<FormLabel>Quantity</FormLabel>
<FormControl>
<NumericFormat
thousandSeparator
allowedDecimalSeparators={["%"]}
decimalScale={2}
{...rest}
customInput={Input}
onValueChange={(values) => {
const { floatValue } = values;
onChange(floatValue);
}}
/>
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
);
}}
/>

<FormField
Expand Down
48 changes: 29 additions & 19 deletions src/components/securities/options/steps/vesting-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,15 @@ import {
StepperPrev,
useStepper,
} from "@/components/ui/stepper";
import { toTitleCase } from "@/lib/string";
import { VestingSchedule } from "@/lib/vesting";
import { VestingScheduleEnum } from "@/prisma/enums";
import { useStockOptionFormValues } from "@/providers/stock-option-form-provider";
import type { RouterOutputs } from "@/trpc/shared";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { NumericFormat } from "react-number-format";
import { z } from "zod";

const vestingSchedule = Object.values(VestingScheduleEnum).map((val) => ({
label: toTitleCase(val).replace("Vesting_", "").replaceAll("_", "-"),
value: val,
}));

const formSchema = z.object({
equityPlanId: z.string(),
vestingSchedule: z.nativeEnum(VestingScheduleEnum),
Expand Down Expand Up @@ -94,13 +90,13 @@ export const VestingDetails = (props: VestingDetailsProps) => {
<Select onValueChange={field.onChange} value={field.value}>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select Vesting" />
<SelectValue placeholder="Select vesting schedule" />
</SelectTrigger>
</FormControl>
<SelectContent>
{vestingSchedule.map((vs) => (
<SelectItem key={vs.value} value={vs.value}>
{vs.label}
{Object.keys(VestingSchedule).map((vKey) => (
<SelectItem key={vKey} value={vKey}>
{VestingSchedule[vKey]}
</SelectItem>
))}
</SelectContent>
Expand Down Expand Up @@ -146,15 +142,29 @@ export const VestingDetails = (props: VestingDetailsProps) => {
<FormField
control={form.control}
name="exercisePrice"
render={({ field }) => (
<FormItem>
<FormLabel>Exercise price</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
)}
render={({ field }) => {
const { onChange, ...rest } = field;
return (
<FormItem>
<FormLabel>Exercise price</FormLabel>
<FormControl>
<NumericFormat
thousandSeparator
allowedDecimalSeparators={["%"]}
decimalScale={2}
prefix={"$ "}
{...rest}
customInput={Input}
onValueChange={(values) => {
const { floatValue } = values;
onChange(floatValue);
}}
/>
</FormControl>
<FormMessage className="text-xs font-light" />
</FormItem>
);
}}
/>

{stakeholders.length ? (
Expand Down
9 changes: 9 additions & 0 deletions src/lib/vesting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const VestingSchedule: { [key: string]: string } = {
VESTING_0_0_0: "Immediate vesting",
VESTING_0_0_1: "1 year cliff with no vesting",
VESTING_4_1_0: "4 years vesting every month with no cliff",
VESTING_4_1_1: "4 years vesting every month with 1 year cliff",
VESTING_4_3_1: "4 years vesting every 3 months with 1 year cliff",
VESTING_4_6_1: "4 years vesting every 6 months with 1 year cliff",
VESTING_4_12_1: "4 years vesting every year with 1 year cliff",
};
2 changes: 1 addition & 1 deletion src/trpc/routers/safe/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const commonSafeSchema = z.object({
safeId: z.string().min(1),
valuationCap: z.coerce.number(),
discountRate: z.coerce.number().optional(),
proRata: z.boolean(),
proRata: z.boolean().optional().default(false),
capital: z.coerce.number(),
issueDate: z.string().date(),
boardApprovalDate: z.string().date(),
Expand Down

0 comments on commit 111bcc6

Please sign in to comment.