feat: add payment module

This commit is contained in:
2025-12-05 01:56:42 +01:00
parent a818f3135a
commit be9b8e9e55
160 changed files with 8615 additions and 1158 deletions

View File

@@ -1,9 +1,9 @@
import { useMemo } from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cva, type VariantProps } from "class-variance-authority";
import { useMemo } from "react";
import { cn } from "@/libraries/utils"
import { Label } from "@/components/ui/label"
import { Separator } from "@/components/ui/separator"
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/libraries/utils";
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
return (
@@ -12,11 +12,11 @@ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
className={cn(
"flex flex-col gap-6",
"has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3",
className
className,
)}
{...props}
/>
)
);
}
function FieldLegend({
@@ -28,15 +28,10 @@ function FieldLegend({
<legend
data-slot="field-legend"
data-variant={variant}
className={cn(
"mb-3 font-medium",
"data-[variant=legend]:text-base",
"data-[variant=label]:text-sm",
className
)}
className={cn("mb-3 font-medium", "data-[variant=legend]:text-base", "data-[variant=label]:text-sm", className)}
{...props}
/>
)
);
}
function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
@@ -45,36 +40,33 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
data-slot="field-group"
className={cn(
"group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4",
className
className,
)}
{...props}
/>
)
);
}
const fieldVariants = cva(
"group/field data-[invalid=true]:text-destructive flex w-full gap-3",
{
variants: {
orientation: {
vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
horizontal: [
"flex-row items-center",
"[&>[data-slot=field-label]]:flex-auto",
"has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px has-[>[data-slot=field-content]]:items-start",
],
responsive: [
"@md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto flex-col [&>*]:w-full [&>.sr-only]:w-auto",
"@md/field-group:[&>[data-slot=field-label]]:flex-auto",
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
},
const fieldVariants = cva("group/field data-[invalid=true]:text-destructive flex w-full gap-3", {
variants: {
orientation: {
vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"],
horizontal: [
"flex-row items-center",
"[&>[data-slot=field-label]]:flex-auto",
"has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px has-[>[data-slot=field-content]]:items-start",
],
responsive: [
"@md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto flex-col [&>*]:w-full [&>.sr-only]:w-auto",
"@md/field-group:[&>[data-slot=field-label]]:flex-auto",
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
],
},
defaultVariants: {
orientation: "vertical",
},
}
)
},
defaultVariants: {
orientation: "vertical",
},
});
function Field({
className,
@@ -89,26 +81,20 @@ function Field({
className={cn(fieldVariants({ orientation }), className)}
{...props}
/>
)
);
}
function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="field-content"
className={cn(
"group/field-content flex flex-1 flex-col gap-1.5 leading-snug",
className
)}
className={cn("group/field-content flex flex-1 flex-col gap-1.5 leading-snug", className)}
{...props}
/>
)
);
}
function FieldLabel({
className,
...props
}: React.ComponentProps<typeof Label>) {
function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>) {
return (
<Label
data-slot="field-label"
@@ -116,11 +102,11 @@ function FieldLabel({
"group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50",
"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>[data-slot=field]]:p-4",
"has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10",
className
className,
)}
{...props}
/>
)
);
}
function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
@@ -129,11 +115,11 @@ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
data-slot="field-label"
className={cn(
"flex w-fit items-center gap-2 text-sm font-medium leading-snug group-data-[disabled=true]/field:opacity-50",
className
className,
)}
{...props}
/>
)
);
}
function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
@@ -144,11 +130,11 @@ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
"text-muted-foreground text-sm font-normal leading-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
"nth-last-2:-mt-1 last:mt-0 [[data-variant=legend]+&]:-mt-1.5",
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
className
className,
)}
{...props}
/>
)
);
}
function FieldSeparator({
@@ -156,16 +142,13 @@ function FieldSeparator({
className,
...props
}: React.ComponentProps<"div"> & {
children?: React.ReactNode
children?: React.ReactNode;
}) {
return (
<div
data-slot="field-separator"
data-content={!!children}
className={cn(
"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2",
className
)}
className={cn("relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", className)}
{...props}
>
<Separator className="absolute inset-0 top-1/2" />
@@ -178,7 +161,7 @@ function FieldSeparator({
</span>
)}
</div>
)
);
}
function FieldError({
@@ -187,33 +170,30 @@ function FieldError({
errors,
...props
}: React.ComponentProps<"div"> & {
errors?: Array<{ message?: string } | undefined>
errors?: Array<{ message?: string } | undefined>;
}) {
const content = useMemo(() => {
if (children) {
return children
return children;
}
if (!errors) {
return null
return null;
}
if (errors?.length === 1 && errors[0]?.message) {
return errors[0].message
return errors[0].message;
}
return (
<ul className="ml-4 flex list-disc flex-col gap-1">
{errors.map(
(error, index) =>
error?.message && <li key={index}>{error.message}</li>
)}
{errors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
</ul>
)
}, [children, errors])
);
}, [children, errors]);
if (!content) {
return null
return null;
}
return (
@@ -225,7 +205,7 @@ function FieldError({
>
{content}
</div>
)
);
}
export {
@@ -239,4 +219,4 @@ export {
FieldSet,
FieldContent,
FieldTitle,
}
};