mirror of
https://github.com/hanzoai/captable.git
synced 2026-10-16 14:21:29 +00:00
fix: migration, input masking and some texts
This commit is contained in:
@@ -659,7 +659,7 @@ model Share {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([companyId,certificateId])
|
||||
@@unique([companyId, certificateId])
|
||||
@@index([companyId])
|
||||
@@index([shareClassId])
|
||||
@@index([stakeholderId])
|
||||
|
||||
@@ -24,15 +24,7 @@ const OptionsPage = async () => {
|
||||
>
|
||||
<OptionModal
|
||||
title="Create an option"
|
||||
subtitle={
|
||||
<Tldr
|
||||
message="Please fill in the details to create an option. If you need help, click the link below."
|
||||
cta={{
|
||||
label: "Learn more",
|
||||
href: "https://captable.inc/help/stakeholder-options",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
subtitle="Please fill in the details to create an option."
|
||||
trigger={
|
||||
<Button size="lg">
|
||||
<RiAddFill className="mr-2 h-5 w-5" />
|
||||
|
||||
@@ -23,20 +23,13 @@ const SharesPage = async () => {
|
||||
subtitle="Please click the button for adding new shares."
|
||||
>
|
||||
<ShareModal
|
||||
size="4xl"
|
||||
title="Create a share"
|
||||
subtitle={
|
||||
<Tldr
|
||||
message="Please fill in the details to create a share. If you need help, click the link below."
|
||||
cta={{
|
||||
label: "Learn more",
|
||||
href: "https://opencap.co/help/stakeholder-shares",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
subtitle="Please fill in the details to create and issue a share."
|
||||
trigger={
|
||||
<Button size="lg">
|
||||
<RiAddFill className="mr-2 h-5 w-5" />
|
||||
Add a share
|
||||
Create a share
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -26,6 +26,7 @@ import { useAddShareFormValues } from "@/providers/add-share-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";
|
||||
import { EmptySelect } from "../../shared/EmptySelect";
|
||||
|
||||
@@ -85,7 +86,7 @@ export const ContributionDetails = ({
|
||||
) : (
|
||||
<EmptySelect
|
||||
title="Stakeholders not found"
|
||||
description="Please add stakeholders in company."
|
||||
description="Please add a stakeholder first."
|
||||
/>
|
||||
)}
|
||||
</SelectContent>
|
||||
@@ -99,30 +100,58 @@ export const ContributionDetails = ({
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="capitalContribution"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Capital contribution</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage className="text-xs font-light" />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
const { onChange, ...rest } = field;
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>Contributed capital amount</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>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="ipContribution"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Intellectual property</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage className="text-xs font-light" />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
const { onChange, ...rest } = field;
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>Value of intellectual property</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>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -131,30 +160,58 @@ export const ContributionDetails = ({
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="debtCancelled"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Debt cancelled</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage className="text-xs font-light" />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
const { onChange, ...rest } = field;
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>Debt cancelled amount</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>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="otherContributions"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Other contributions</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage className="text-xs font-light" />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
const { onChange, ...rest } = field;
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>Other contributed amount</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>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
import { EmptySelect } from "@/components/securities/shared/EmptySelect";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
@@ -29,6 +30,7 @@ import {
|
||||
StepperPrev,
|
||||
useStepper,
|
||||
} from "@/components/ui/stepper";
|
||||
import { VestingSchedule } from "@/lib/vesting";
|
||||
import {
|
||||
SecuritiesStatusEnum,
|
||||
ShareLegendsEnum,
|
||||
@@ -38,38 +40,17 @@ import { useAddShareFormValues } from "@/providers/add-share-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";
|
||||
import { EmptySelect } from "../../shared/EmptySelect";
|
||||
|
||||
export const humanizeCompanyLegends = (type: string): string => {
|
||||
switch (type) {
|
||||
case ShareLegendsEnum.US_SECURITIES_ACT:
|
||||
return "Us securities act";
|
||||
return "US Securities Act";
|
||||
case ShareLegendsEnum.TRANSFER_RESTRICTIONS:
|
||||
return "Transfer restrictions";
|
||||
return "Transfer Restrictions";
|
||||
case ShareLegendsEnum.SALE_AND_ROFR:
|
||||
return "Sale and Rofr";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
export const humanizeVestingSchedule = (type: string): string => {
|
||||
switch (type) {
|
||||
case VestingScheduleEnum.VESTING_0_0_0:
|
||||
return "Immediate vesting";
|
||||
case VestingScheduleEnum.VESTING_0_0_1:
|
||||
return "1 year cliff with no vesting";
|
||||
case VestingScheduleEnum.VESTING_4_1_0:
|
||||
return "4 years vesting every month with no cliff";
|
||||
case VestingScheduleEnum.VESTING_4_1_1:
|
||||
return "4 years vesting every month with 1 year cliff";
|
||||
case VestingScheduleEnum.VESTING_4_3_1:
|
||||
return "4 years vesting every 3 months with 1 year cliff";
|
||||
case VestingScheduleEnum.VESTING_4_6_1:
|
||||
return "4 years vesting every 6 months with 1 year cliff";
|
||||
case VestingScheduleEnum.VESTING_4_12_1:
|
||||
return "4 years vesting every year with 1 year cliff";
|
||||
return "Sale and ROFR";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@@ -139,11 +120,10 @@ export const GeneralDetails = ({ shareClasses }: GeneralDetailsProps) => {
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Share class</FormLabel>
|
||||
{/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */}
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select shareclass" />
|
||||
<SelectValue placeholder="Select a share class" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
@@ -155,8 +135,8 @@ export const GeneralDetails = ({ shareClasses }: GeneralDetailsProps) => {
|
||||
))
|
||||
) : (
|
||||
<EmptySelect
|
||||
title="ShareClass not found"
|
||||
description="Please add required shareclass."
|
||||
title="Share class not found!"
|
||||
description="Please add required share class."
|
||||
/>
|
||||
)}
|
||||
</SelectContent>
|
||||
@@ -204,30 +184,57 @@ export const GeneralDetails = ({ shareClasses }: GeneralDetailsProps) => {
|
||||
<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>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="pricePerShare"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Price per share</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage className="text-xs font-light" />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
const { onChange, ...rest } = field;
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>Price per share</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>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -244,14 +251,14 @@ export const GeneralDetails = ({ shareClasses }: GeneralDetailsProps) => {
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select Vesting" />
|
||||
<SelectValue placeholder="Select vesting schedule" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{vestingSchedule?.length &&
|
||||
vestingSchedule.map((vs) => (
|
||||
<SelectItem key={vs} value={vs}>
|
||||
{humanizeVestingSchedule(vs)}
|
||||
{VestingSchedule[vs]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
@@ -266,14 +273,16 @@ export const GeneralDetails = ({ shareClasses }: GeneralDetailsProps) => {
|
||||
name="companyLegends"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Company Legends</FormLabel>
|
||||
<FormLabel>Company legends</FormLabel>
|
||||
<MultiSelector
|
||||
onValuesChange={field.onChange}
|
||||
//@ts-ignore
|
||||
values={field.value}
|
||||
>
|
||||
<MultiSelectorTrigger>
|
||||
<MultiSelectorInput placeholder="Select company legends" />
|
||||
<MultiSelectorInput
|
||||
className="text-sm"
|
||||
placeholder="Select company legends"
|
||||
/>
|
||||
</MultiSelectorTrigger>
|
||||
<MultiSelectorContent>
|
||||
<MultiSelectorList>
|
||||
|
||||
Reference in New Issue
Block a user