startx 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +4 -0
- package/apps/cli/src/commands/index.ts +1 -1
- package/apps/cli/src/commands/{common → test}/test.ts +4 -2
- package/apps/cli/tsconfig.json +0 -1
- package/apps/core-server/Dockerfile +5 -4
- package/apps/core-server/package.json +1 -1
- package/apps/core-server/tsconfig.json +1 -1
- package/apps/queue-worker/package.json +1 -1
- package/apps/queue-worker/tsconfig.json +1 -1
- package/apps/startx-cli/dist/index.mjs +68 -53
- package/apps/startx-cli/src/commands/package.ts +453 -0
- package/apps/startx-cli/src/configs/scripts.ts +18 -2
- package/apps/startx-cli/src/index.ts +2 -4
- package/apps/startx-cli/src/types.ts +2 -4
- package/apps/startx-cli/src/utils/inquirer.ts +8 -1
- package/apps/web-client/.dockerignore +4 -0
- package/apps/web-client/app/app.css +1 -0
- package/apps/web-client/app/components.json +23 -0
- package/apps/web-client/app/config/auth/auth-state.ts +59 -0
- package/apps/web-client/app/config/axios-client.ts +87 -0
- package/apps/web-client/app/config/env.ts +5 -0
- package/apps/web-client/app/entry.client.tsx +7 -0
- package/apps/web-client/app/eslint.config.ts +4 -0
- package/apps/web-client/app/root.tsx +77 -0
- package/apps/web-client/app/routes/home.tsx +12 -0
- package/apps/web-client/app/routes.ts +3 -0
- package/apps/web-client/eslint.config.ts +4 -0
- package/apps/web-client/package.json +55 -0
- package/apps/web-client/react-router.config.ts +7 -0
- package/apps/web-client/tsconfig.json +22 -0
- package/apps/web-client/vite-env.d.ts +8 -0
- package/apps/web-client/vite.config.ts +30 -0
- package/biome.json +5 -0
- package/configs/eslint-config/eslint.config.ts +1 -0
- package/configs/eslint-config/src/configs/base.ts +0 -1
- package/configs/eslint-config/src/configs/frontend.ts +1 -1
- package/configs/eslint-config/tsconfig.json +1 -1
- package/configs/typescript-config/tsconfig.frontend.json +1 -1
- package/configs/vitest-config/tsconfig.json +1 -1
- package/package.json +1 -1
- package/packages/@db/drizzle/tsconfig.json +1 -1
- package/packages/@db/sqlite/tsconfig.json +1 -1
- package/packages/@repo/env/package.json +1 -2
- package/packages/@repo/env/src/utils.ts +17 -11
- package/packages/@repo/lib/package.json +3 -1
- package/packages/@repo/lib/src/session-module/i-session.ts +108 -0
- package/packages/@repo/lib/src/session-module/index.ts +8 -111
- package/packages/@repo/lib/src/session-module/redis-session.ts +44 -0
- package/packages/@repo/lib/tsconfig.json +0 -1
- package/packages/@repo/logger/package.json +0 -1
- package/packages/@repo/logger/tsconfig.json +1 -1
- package/packages/@repo/mail/tsconfig.json +1 -1
- package/packages/@repo/redis/tsconfig.json +1 -1
- package/packages/aix/package.json +2 -0
- package/packages/aix/src/providers/ai-interface.ts +4 -4
- package/packages/aix/src/providers/bedrock/bedrock.ts +261 -0
- package/packages/aix/src/providers/default-models.ts +65 -0
- package/packages/aix/src/providers/openai/openai.ts +2 -2
- package/packages/aix/src/providers/providers.ts +11 -0
- package/packages/aix/src/providers/types.ts +1 -1
- package/packages/{constants → common}/package.json +4 -2
- package/packages/{constants/src/index.ts → common/src/constants.ts} +0 -5
- package/packages/common/src/types/users.ts +10 -0
- package/packages/{constants → common}/tsconfig.json +0 -3
- package/packages/ui/components.json +15 -8
- package/packages/ui/package.json +23 -36
- package/packages/ui/src/api/axios/i-client.ts +40 -0
- package/packages/ui/src/api/index.ts +6 -0
- package/packages/ui/src/api/query-provider.tsx +34 -0
- package/packages/ui/src/api/use-api/api-builder.ts +139 -0
- package/packages/ui/src/api/use-api/api-helpers.ts +165 -0
- package/packages/ui/src/api/use-api/api-types.ts +138 -0
- package/packages/ui/src/api/use-api/query-factory.ts +66 -0
- package/packages/ui/src/api/use-api/react-query/types.ts +64 -0
- package/packages/ui/src/api/use-api/react-query/use-api-client.ts +56 -0
- package/packages/ui/src/api/use-api/react-query/use-api.ts +297 -0
- package/packages/ui/src/components/custom/form-wrapper.tsx +113 -160
- package/packages/ui/src/components/custom/grid-component.tsx +4 -4
- package/packages/ui/src/components/custom/hover-tool.tsx +1 -1
- package/packages/ui/src/components/custom/image-picker.tsx +18 -20
- package/packages/ui/src/components/custom/no-content.tsx +6 -16
- package/packages/ui/src/components/custom/page-section.tsx +14 -17
- package/packages/ui/src/components/custom/simple-popover.tsx +5 -9
- package/packages/ui/src/components/custom/theme-provider.tsx +117 -42
- package/packages/ui/src/components/custom/typography.tsx +20 -22
- package/packages/ui/src/components/extensions/timeline.tsx +100 -0
- package/packages/ui/src/components/ui/alert-dialog.tsx +46 -108
- package/packages/ui/src/components/ui/avatar.tsx +79 -42
- package/packages/ui/src/components/ui/badge.tsx +29 -34
- package/packages/ui/src/components/ui/breadcrumb.tsx +65 -81
- package/packages/ui/src/components/ui/button.tsx +80 -80
- package/packages/ui/src/components/ui/card.tsx +48 -69
- package/packages/ui/src/components/ui/carousel.tsx +184 -211
- package/packages/ui/src/components/ui/checkbox.tsx +21 -24
- package/packages/ui/src/components/ui/command.tsx +121 -102
- package/packages/ui/src/components/ui/dialog.tsx +45 -32
- package/packages/ui/src/components/ui/dropdown-menu.tsx +45 -33
- package/packages/ui/src/components/ui/field.tsx +218 -0
- package/packages/ui/src/components/ui/form.tsx +63 -76
- package/packages/ui/src/components/ui/input-group.tsx +137 -0
- package/packages/ui/src/components/ui/input-otp.tsx +60 -50
- package/packages/ui/src/components/ui/input.tsx +16 -15
- package/packages/ui/src/components/ui/label.tsx +14 -17
- package/packages/ui/src/components/ui/multiple-select.tsx +22 -33
- package/packages/ui/src/components/ui/popover.tsx +20 -8
- package/packages/ui/src/components/ui/select.tsx +33 -34
- package/packages/ui/src/components/ui/separator.tsx +8 -8
- package/packages/ui/src/components/ui/sheet.tsx +32 -59
- package/packages/ui/src/components/ui/sidebar.tsx +654 -0
- package/packages/ui/src/components/ui/skeleton.tsx +2 -8
- package/packages/ui/src/components/ui/sonner.tsx +39 -0
- package/packages/ui/src/components/ui/spinner.tsx +6 -13
- package/packages/ui/src/components/ui/switch.tsx +15 -10
- package/packages/ui/src/components/ui/table.tsx +48 -89
- package/packages/ui/src/components/ui/tabs.tsx +37 -15
- package/packages/ui/src/components/ui/textarea.tsx +13 -13
- package/packages/ui/src/components/ui/tooltip.tsx +37 -23
- package/packages/ui/src/{components/hooks → hooks}/event/use-click.tsx +6 -10
- package/packages/ui/src/hooks/time/use-timer.tsx +51 -0
- package/packages/ui/src/hooks/use-media-query.tsx +19 -0
- package/packages/ui/src/hooks/use-mobile.tsx +17 -0
- package/packages/ui/src/{components/hooks → hooks}/use-update-effect.tsx +2 -2
- package/packages/ui/src/lib/utils.ts +113 -0
- package/packages/ui/src/styles/globals.css +311 -0
- package/packages/ui/src/styles/tailwind.css +89 -0
- package/packages/ui/tsconfig.json +7 -9
- package/pnpm-workspace.yaml +74 -64
- package/packages/ui/postcss.config.mjs +0 -9
- package/packages/ui/src/components/extensions/carousel.tsx +0 -392
- package/packages/ui/src/components/hooks/time/useTimer.tsx +0 -51
- package/packages/ui/src/components/hooks/use-media-query.tsx +0 -19
- package/packages/ui/src/components/lib/utils.ts +0 -242
- package/packages/ui/src/components/ui/timeline.tsx +0 -118
- package/packages/ui/src/components/util/n-formattor.ts +0 -22
- package/packages/ui/src/components/util/storage.ts +0 -37
- package/packages/ui/src/globals.css +0 -87
- package/packages/ui/tailwind.config.ts +0 -94
- /package/packages/{constants → common}/eslint.config.ts +0 -0
- /package/packages/{constants → common}/src/api.ts +0 -0
- /package/packages/{constants → common}/src/time.ts +0 -0
- /package/packages/{constants → common}/vitest.config.ts +0 -0
- /package/packages/ui/src/{components/hooks/time/useDebounce.tsx → hooks/time/use-debounce.tsx} +0 -0
- /package/packages/ui/src/{components/hooks/time/useInterval.tsx → hooks/time/use-interval.tsx} +0 -0
- /package/packages/ui/src/{components/hooks/time/useTimeout.tsx → hooks/time/use-timeout.tsx} +0 -0
- /package/packages/ui/src/{components/hooks → hooks}/use-persistent-storage.tsx +0 -0
- /package/packages/ui/src/{components/hooks → hooks}/use-window-dimension.tsx +0 -0
- /package/packages/ui/src/{components/sonner.tsx → sonner.ts} +0 -0
|
@@ -11,40 +11,16 @@ import {
|
|
|
11
11
|
useFieldArray,
|
|
12
12
|
} from "react-hook-form";
|
|
13
13
|
import type { ClassNameValue } from "tailwind-merge";
|
|
14
|
-
import type { z } from "zod";
|
|
15
14
|
|
|
16
|
-
import { cn } from "
|
|
15
|
+
import { cn } from "@repo/ui/lib/utils";
|
|
17
16
|
import { Badge } from "../ui/badge";
|
|
18
17
|
import { Button } from "../ui/button";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
CommandGroup,
|
|
23
|
-
CommandInput,
|
|
24
|
-
CommandItem,
|
|
25
|
-
CommandList,
|
|
26
|
-
} from "../ui/command";
|
|
27
|
-
import {
|
|
28
|
-
Form,
|
|
29
|
-
FormControl,
|
|
30
|
-
FormDescription,
|
|
31
|
-
FormField,
|
|
32
|
-
FormItem,
|
|
33
|
-
FormLabel,
|
|
34
|
-
FormMessage,
|
|
35
|
-
} from "../ui/form";
|
|
18
|
+
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "../ui/command";
|
|
19
|
+
import { Field, FieldContent, FieldDescription, FieldError, FieldLabel } from "../ui/field";
|
|
20
|
+
import { Form, FormField } from "../ui/form";
|
|
36
21
|
import { Input, type InputProps } from "../ui/input";
|
|
37
|
-
import { Label } from "../ui/label";
|
|
38
22
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
39
|
-
import {
|
|
40
|
-
Select,
|
|
41
|
-
SelectContent,
|
|
42
|
-
SelectGroup,
|
|
43
|
-
SelectItem,
|
|
44
|
-
SelectLabel,
|
|
45
|
-
SelectTrigger,
|
|
46
|
-
SelectValue,
|
|
47
|
-
} from "../ui/select";
|
|
23
|
+
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select";
|
|
48
24
|
import { Textarea } from "../ui/textarea";
|
|
49
25
|
|
|
50
26
|
type SimpleFormFieldProps = {
|
|
@@ -61,12 +37,12 @@ type RelationSelectOption = {
|
|
|
61
37
|
}>;
|
|
62
38
|
};
|
|
63
39
|
|
|
64
|
-
type FormSelectFieldProps<
|
|
65
|
-
TFieldValues
|
|
66
|
-
|
|
67
|
-
>
|
|
68
|
-
label?: ReactNode;
|
|
69
|
-
options: Array<SelectOption | RelationSelectOption>;
|
|
40
|
+
type FormSelectFieldProps<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>> = Omit<
|
|
41
|
+
ControllerProps<TFieldValues, TName>,
|
|
42
|
+
"render"
|
|
43
|
+
> & {
|
|
44
|
+
label?: ReactNode;
|
|
45
|
+
options: Array<SelectOption | RelationSelectOption>;
|
|
70
46
|
className?: ClassNameValue;
|
|
71
47
|
placeholder?: ReactNode;
|
|
72
48
|
onChange?: (value: string) => void;
|
|
@@ -97,31 +73,28 @@ export const FormSelectField = <
|
|
|
97
73
|
}): Array<SelectOption | RelationSelectOption> => {
|
|
98
74
|
if (!defaultValue) return [...options];
|
|
99
75
|
|
|
100
|
-
// Check if defaultValue exists in either flat options or nested group options
|
|
101
76
|
const valueExists = options.some(opt => {
|
|
102
77
|
if ("options" in opt) {
|
|
103
|
-
// Check nested options in RelationSelectOption group
|
|
104
78
|
return opt.options.some(nestedOpt => nestedOpt.value === defaultValue);
|
|
105
79
|
}
|
|
106
|
-
// Check regular SelectOption
|
|
107
80
|
return opt.value === defaultValue;
|
|
108
81
|
});
|
|
109
82
|
|
|
110
83
|
if (!valueExists) {
|
|
111
|
-
// Prepend the default value as a new option
|
|
112
84
|
return [{ label: defaultValue, value: defaultValue }, ...options];
|
|
113
85
|
}
|
|
114
86
|
|
|
115
87
|
return [...options];
|
|
116
88
|
};
|
|
89
|
+
|
|
117
90
|
return (
|
|
118
91
|
<FormField
|
|
119
92
|
control={control}
|
|
120
93
|
name={name}
|
|
121
|
-
render={({ field }) => (
|
|
122
|
-
<
|
|
123
|
-
<
|
|
124
|
-
<
|
|
94
|
+
render={({ field, fieldState }) => (
|
|
95
|
+
<Field data-invalid={!!fieldState.error} className={cn("flex flex-col", className)}>
|
|
96
|
+
{label ? <FieldLabel className="self-start">{label}</FieldLabel> : null}
|
|
97
|
+
<FieldContent>
|
|
125
98
|
<Select
|
|
126
99
|
disabled={disabled}
|
|
127
100
|
onValueChange={value => {
|
|
@@ -155,42 +128,43 @@ export const FormSelectField = <
|
|
|
155
128
|
})}
|
|
156
129
|
</SelectContent>
|
|
157
130
|
</Select>
|
|
158
|
-
</
|
|
159
|
-
<
|
|
160
|
-
</
|
|
131
|
+
</FieldContent>
|
|
132
|
+
<FieldError errors={[fieldState.error]} />
|
|
133
|
+
</Field>
|
|
161
134
|
)}
|
|
162
135
|
/>
|
|
163
136
|
);
|
|
164
137
|
};
|
|
138
|
+
|
|
165
139
|
export const FormTextField = <
|
|
166
140
|
TFieldValues extends FieldValues = FieldValues,
|
|
167
141
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
168
142
|
>(
|
|
169
143
|
props: Omit<
|
|
170
|
-
SimpleFormFieldProps &
|
|
171
|
-
ControllerProps<TFieldValues, TName> &
|
|
172
|
-
InputProps &
|
|
173
|
-
React.RefAttributes<HTMLInputElement>,
|
|
144
|
+
SimpleFormFieldProps & ControllerProps<TFieldValues, TName> & InputProps & React.RefAttributes<HTMLInputElement>,
|
|
174
145
|
"render"
|
|
175
146
|
>
|
|
176
147
|
) => {
|
|
148
|
+
const { label, description, control, name, ...rest } = props;
|
|
149
|
+
|
|
177
150
|
return (
|
|
178
151
|
<FormField
|
|
179
|
-
control={
|
|
180
|
-
name={
|
|
181
|
-
render={({ field }) => (
|
|
182
|
-
<
|
|
183
|
-
<
|
|
184
|
-
<
|
|
185
|
-
<Input {...field} {...
|
|
186
|
-
</
|
|
187
|
-
{
|
|
188
|
-
<
|
|
189
|
-
</
|
|
152
|
+
control={control}
|
|
153
|
+
name={name}
|
|
154
|
+
render={({ field, fieldState }) => (
|
|
155
|
+
<Field data-invalid={!!fieldState.error} className="flex flex-col">
|
|
156
|
+
{label ? <FieldLabel className="self-start">{label}</FieldLabel> : null}
|
|
157
|
+
<FieldContent>
|
|
158
|
+
<Input {...field} {...rest} />
|
|
159
|
+
</FieldContent>
|
|
160
|
+
{description ? <FieldDescription>{description}</FieldDescription> : null}
|
|
161
|
+
<FieldError errors={[fieldState.error]} />
|
|
162
|
+
</Field>
|
|
190
163
|
)}
|
|
191
164
|
/>
|
|
192
165
|
);
|
|
193
166
|
};
|
|
167
|
+
|
|
194
168
|
export const FormTextAreaField = <
|
|
195
169
|
TFieldValues extends FieldValues = FieldValues,
|
|
196
170
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
@@ -203,56 +177,57 @@ export const FormTextAreaField = <
|
|
|
203
177
|
"render"
|
|
204
178
|
>
|
|
205
179
|
) => {
|
|
180
|
+
const { label, description, control, name, ...rest } = props;
|
|
181
|
+
|
|
206
182
|
return (
|
|
207
183
|
<FormField
|
|
208
|
-
control={
|
|
209
|
-
name={
|
|
210
|
-
render={({ field }) => (
|
|
211
|
-
<
|
|
212
|
-
{
|
|
213
|
-
<
|
|
214
|
-
<Textarea {...field} {...
|
|
215
|
-
</
|
|
216
|
-
{
|
|
217
|
-
<
|
|
218
|
-
</
|
|
184
|
+
control={control}
|
|
185
|
+
name={name}
|
|
186
|
+
render={({ field, fieldState }) => (
|
|
187
|
+
<Field data-invalid={!!fieldState.error} className="flex flex-col">
|
|
188
|
+
{label ? <FieldLabel className="self-start">{label}</FieldLabel> : null}
|
|
189
|
+
<FieldContent>
|
|
190
|
+
<Textarea {...field} {...rest} ref={field.ref} />
|
|
191
|
+
</FieldContent>
|
|
192
|
+
{description ? <FieldDescription>{description}</FieldDescription> : null}
|
|
193
|
+
<FieldError errors={[fieldState.error]} />
|
|
194
|
+
</Field>
|
|
219
195
|
)}
|
|
220
196
|
/>
|
|
221
197
|
);
|
|
222
198
|
};
|
|
199
|
+
|
|
223
200
|
export const FormNumberField = <
|
|
224
201
|
TFieldValues extends FieldValues = FieldValues,
|
|
225
202
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
226
203
|
>(
|
|
227
204
|
props: Omit<
|
|
228
|
-
SimpleFormFieldProps &
|
|
229
|
-
ControllerProps<TFieldValues, TName> &
|
|
230
|
-
InputProps &
|
|
231
|
-
React.RefAttributes<HTMLInputElement>,
|
|
205
|
+
SimpleFormFieldProps & ControllerProps<TFieldValues, TName> & InputProps & React.RefAttributes<HTMLInputElement>,
|
|
232
206
|
"render"
|
|
233
207
|
>
|
|
234
208
|
) => {
|
|
209
|
+
const { label, description, control, name, ...rest } = props;
|
|
210
|
+
|
|
235
211
|
return (
|
|
236
212
|
<FormField
|
|
237
|
-
control={
|
|
238
|
-
name={
|
|
239
|
-
render={({ field }) => (
|
|
240
|
-
<
|
|
241
|
-
<
|
|
242
|
-
<
|
|
213
|
+
control={control}
|
|
214
|
+
name={name}
|
|
215
|
+
render={({ field, fieldState }) => (
|
|
216
|
+
<Field data-invalid={!!fieldState.error} className="flex flex-col">
|
|
217
|
+
{label ? <FieldLabel className="self-start">{label}</FieldLabel> : null}
|
|
218
|
+
<FieldContent>
|
|
243
219
|
<Input
|
|
244
220
|
inputMode="numeric"
|
|
245
221
|
{...field}
|
|
246
222
|
onChange={e => {
|
|
247
|
-
if (!isNaN(Number(e.currentTarget.value)))
|
|
248
|
-
field.onChange(Number(e.currentTarget.value));
|
|
223
|
+
if (!isNaN(Number(e.currentTarget.value))) field.onChange(Number(e.currentTarget.value));
|
|
249
224
|
}}
|
|
250
|
-
{...
|
|
225
|
+
{...rest}
|
|
251
226
|
/>
|
|
252
|
-
</
|
|
253
|
-
{
|
|
254
|
-
<
|
|
255
|
-
</
|
|
227
|
+
</FieldContent>
|
|
228
|
+
{description ? <FieldDescription>{description}</FieldDescription> : null}
|
|
229
|
+
<FieldError errors={[fieldState.error]} />
|
|
230
|
+
</Field>
|
|
256
231
|
)}
|
|
257
232
|
/>
|
|
258
233
|
);
|
|
@@ -260,24 +235,21 @@ export const FormNumberField = <
|
|
|
260
235
|
|
|
261
236
|
export type FormWrapperProps<T extends FieldValues> = {
|
|
262
237
|
onSubmit: (data: T) => void;
|
|
263
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
264
238
|
formData: UseFormReturn<T, unknown, any>;
|
|
265
239
|
children: React.ReactNode;
|
|
266
240
|
className?: string;
|
|
267
241
|
};
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
name: K;
|
|
242
|
+
type MultipleFormItemProps<TFieldValues extends FieldValues, TName extends ArrayPath<TFieldValues>> = {
|
|
243
|
+
control: Control<TFieldValues>;
|
|
244
|
+
name: TName;
|
|
272
245
|
label?: string;
|
|
273
|
-
addMoreBtn?:
|
|
246
|
+
addMoreBtn?: ReactNode;
|
|
274
247
|
className?: ClassNameValue;
|
|
275
248
|
wrapperClassName?: ClassNameValue;
|
|
276
|
-
children: (field: { id: string; index: number; remove: () => void }) =>
|
|
277
|
-
defaultValue:
|
|
249
|
+
children: (field: { id: string; index: number; remove: () => void }) => ReactNode;
|
|
250
|
+
defaultValue: TFieldValues[TName] extends Array<infer U> ? U : never;
|
|
278
251
|
};
|
|
279
|
-
|
|
280
|
-
export const MultipleFormItem = <T extends z.ZodType, K extends ArrayPath<z.infer<T>>>({
|
|
252
|
+
export const MultipleFormItem = <TFieldValues extends FieldValues, TName extends ArrayPath<TFieldValues>>({
|
|
281
253
|
control,
|
|
282
254
|
name,
|
|
283
255
|
addMoreBtn,
|
|
@@ -286,7 +258,7 @@ export const MultipleFormItem = <T extends z.ZodType, K extends ArrayPath<z.infe
|
|
|
286
258
|
wrapperClassName,
|
|
287
259
|
className,
|
|
288
260
|
defaultValue,
|
|
289
|
-
}: MultipleFormItemProps<
|
|
261
|
+
}: MultipleFormItemProps<TFieldValues, TName>) => {
|
|
290
262
|
const { fields, append, remove } = useFieldArray({
|
|
291
263
|
control,
|
|
292
264
|
name,
|
|
@@ -294,7 +266,7 @@ export const MultipleFormItem = <T extends z.ZodType, K extends ArrayPath<z.infe
|
|
|
294
266
|
|
|
295
267
|
return (
|
|
296
268
|
<div className="multiple-form-item">
|
|
297
|
-
{label ? <p className="mt-6 text-sm
|
|
269
|
+
{label ? <p className="mt-6 text-sm">{label}</p> : null}
|
|
298
270
|
<div className={cn(wrapperClassName)}>
|
|
299
271
|
{fields.map((field, index) => (
|
|
300
272
|
<div key={field.id} className={cn("flex flex-col gap-2 max-w-xl", className)}>
|
|
@@ -302,14 +274,14 @@ export const MultipleFormItem = <T extends z.ZodType, K extends ArrayPath<z.infe
|
|
|
302
274
|
</div>
|
|
303
275
|
))}
|
|
304
276
|
{addMoreBtn ? (
|
|
305
|
-
<
|
|
277
|
+
<Button onClick={() => append(defaultValue as any)}>{addMoreBtn}</Button>
|
|
306
278
|
) : (
|
|
307
279
|
<Button
|
|
308
280
|
className="w-1/3 mt-4 flex gap-1"
|
|
309
281
|
variant="outline"
|
|
310
282
|
type="button"
|
|
311
283
|
size={"sm"}
|
|
312
|
-
onClick={() => append(defaultValue)}
|
|
284
|
+
onClick={() => append(defaultValue as any)}
|
|
313
285
|
>
|
|
314
286
|
<Plus />
|
|
315
287
|
<span>Add {label?.toLowerCase() ?? "item"}</span>
|
|
@@ -319,7 +291,6 @@ export const MultipleFormItem = <T extends z.ZodType, K extends ArrayPath<z.infe
|
|
|
319
291
|
</div>
|
|
320
292
|
);
|
|
321
293
|
};
|
|
322
|
-
|
|
323
294
|
export function FormWrapper<T extends FieldValues>(props: FormWrapperProps<T>) {
|
|
324
295
|
return (
|
|
325
296
|
<Form {...props.formData}>
|
|
@@ -343,25 +314,22 @@ export const FormDefaultDateField = <
|
|
|
343
314
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
344
315
|
>(
|
|
345
316
|
props: Omit<
|
|
346
|
-
SimpleFormFieldProps &
|
|
347
|
-
ControllerProps<TFieldValues, TName> &
|
|
348
|
-
InputProps &
|
|
349
|
-
React.RefAttributes<HTMLInputElement>,
|
|
317
|
+
SimpleFormFieldProps & ControllerProps<TFieldValues, TName> & InputProps & React.RefAttributes<HTMLInputElement>,
|
|
350
318
|
"render"
|
|
351
319
|
>
|
|
352
320
|
) => {
|
|
321
|
+
const { label, description, control, name, ...rest } = props;
|
|
322
|
+
|
|
353
323
|
const safeFormat = (date: Date | string | undefined | null) => {
|
|
354
324
|
try {
|
|
355
325
|
if (!date) return undefined;
|
|
356
326
|
|
|
357
327
|
const parsedDate = typeof date === "string" ? new Date(date) : date;
|
|
358
328
|
|
|
359
|
-
// Extract UTC date components
|
|
360
329
|
const year = parsedDate.getUTCFullYear();
|
|
361
330
|
const month = parsedDate.getUTCMonth();
|
|
362
331
|
const day = parsedDate.getUTCDate();
|
|
363
332
|
|
|
364
|
-
// Create a Date object at midnight UTC
|
|
365
333
|
const utcMidnight = new Date(Date.UTC(year, month, day));
|
|
366
334
|
return format(utcMidnight, "yyyy-MM-dd");
|
|
367
335
|
} catch (error) {
|
|
@@ -373,15 +341,12 @@ export const FormDefaultDateField = <
|
|
|
373
341
|
try {
|
|
374
342
|
if (!dateString) return undefined;
|
|
375
343
|
|
|
376
|
-
// Parse input date as local time
|
|
377
344
|
const localDate = new Date(dateString);
|
|
378
345
|
|
|
379
|
-
// Get local date components
|
|
380
346
|
const year = localDate.getFullYear();
|
|
381
347
|
const month = localDate.getMonth();
|
|
382
348
|
const day = localDate.getDate();
|
|
383
349
|
|
|
384
|
-
// Create Date object at midnight UTC of the local date
|
|
385
350
|
return new Date(Date.UTC(year, month, day));
|
|
386
351
|
} catch (error) {
|
|
387
352
|
console.error(error);
|
|
@@ -391,32 +356,33 @@ export const FormDefaultDateField = <
|
|
|
391
356
|
|
|
392
357
|
return (
|
|
393
358
|
<FormField
|
|
394
|
-
control={
|
|
395
|
-
name={
|
|
396
|
-
render={({ field }) => (
|
|
397
|
-
<
|
|
398
|
-
<
|
|
399
|
-
<
|
|
359
|
+
control={control}
|
|
360
|
+
name={name}
|
|
361
|
+
render={({ field, fieldState }) => (
|
|
362
|
+
<Field data-invalid={!!fieldState.error} className="flex flex-col">
|
|
363
|
+
{label ? <FieldLabel className="self-start">{label}</FieldLabel> : null}
|
|
364
|
+
<FieldContent>
|
|
400
365
|
<Input
|
|
401
366
|
{...field}
|
|
402
|
-
{...
|
|
367
|
+
{...rest}
|
|
403
368
|
value={field.value || ""}
|
|
404
369
|
onChange={e => field.onChange(e.target.value)}
|
|
405
370
|
type="date"
|
|
406
371
|
max="9999-12-31"
|
|
407
372
|
/>
|
|
408
|
-
</
|
|
409
|
-
{
|
|
410
|
-
<
|
|
411
|
-
</
|
|
373
|
+
</FieldContent>
|
|
374
|
+
{description ? <FieldDescription>{description}</FieldDescription> : null}
|
|
375
|
+
<FieldError errors={[fieldState.error]} />
|
|
376
|
+
</Field>
|
|
412
377
|
)}
|
|
413
378
|
/>
|
|
414
379
|
);
|
|
415
380
|
};
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
381
|
+
|
|
382
|
+
type FormMultiSelectFieldProps<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>> = Omit<
|
|
383
|
+
ControllerProps<TFieldValues, TName>,
|
|
384
|
+
"render"
|
|
385
|
+
> & {
|
|
420
386
|
label?: React.ReactNode;
|
|
421
387
|
options: Array<SelectOption | RelationSelectOption>;
|
|
422
388
|
className?: string;
|
|
@@ -449,33 +415,23 @@ export function FormMultiSelectField<
|
|
|
449
415
|
control={control}
|
|
450
416
|
name={name}
|
|
451
417
|
defaultValue={defaultValue}
|
|
452
|
-
render={({ field }) => {
|
|
418
|
+
render={({ field, fieldState }) => {
|
|
453
419
|
const selected: string[] = field.value ?? [];
|
|
454
420
|
|
|
455
421
|
const toggleOption = (value: string) => {
|
|
456
|
-
const newValue = selected.includes(value)
|
|
457
|
-
? selected.filter(v => v !== value)
|
|
458
|
-
: [...selected, value];
|
|
422
|
+
const newValue = selected.includes(value) ? selected.filter(v => v !== value) : [...selected, value];
|
|
459
423
|
field.onChange(newValue);
|
|
460
424
|
onChange?.(newValue);
|
|
461
425
|
};
|
|
462
426
|
|
|
463
427
|
return (
|
|
464
|
-
<
|
|
465
|
-
{label ? <
|
|
466
|
-
<
|
|
428
|
+
<Field data-invalid={!!fieldState.error} className={cn("flex flex-col", className)}>
|
|
429
|
+
{label ? <FieldLabel>{label}</FieldLabel> : null}
|
|
430
|
+
<FieldContent className="w-full">
|
|
467
431
|
<Popover open={open} onOpenChange={setOpen}>
|
|
468
432
|
<PopoverTrigger asChild disabled={disabled}>
|
|
469
|
-
<Button
|
|
470
|
-
|
|
471
|
-
// role="combobox"
|
|
472
|
-
size={"sm"}
|
|
473
|
-
// aria-expanded={open}
|
|
474
|
-
className={cn("w-full justify-between", inputClassName)}
|
|
475
|
-
>
|
|
476
|
-
{selected.length > 0
|
|
477
|
-
? `${selected.length} selected`
|
|
478
|
-
: (placeholder ?? "Select")}
|
|
433
|
+
<Button variant="outline" size={"sm"} className={cn("w-full justify-between", inputClassName)}>
|
|
434
|
+
{selected.length > 0 ? `${selected.length} selected` : (placeholder ?? "Select")}
|
|
479
435
|
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
|
480
436
|
</Button>
|
|
481
437
|
</PopoverTrigger>
|
|
@@ -489,10 +445,7 @@ export function FormMultiSelectField<
|
|
|
489
445
|
"options" in opt ? (
|
|
490
446
|
<CommandGroup key={opt.label} heading={opt.label}>
|
|
491
447
|
{opt.options.map(nested => (
|
|
492
|
-
<CommandItem
|
|
493
|
-
key={nested.value}
|
|
494
|
-
onSelect={() => toggleOption(nested.value)}
|
|
495
|
-
>
|
|
448
|
+
<CommandItem key={nested.value} onSelect={() => toggleOption(nested.value)}>
|
|
496
449
|
<Check
|
|
497
450
|
className={cn(
|
|
498
451
|
"mr-2 h-4 w-4",
|
|
@@ -520,30 +473,30 @@ export function FormMultiSelectField<
|
|
|
520
473
|
</PopoverContent>
|
|
521
474
|
</div>
|
|
522
475
|
</Popover>
|
|
523
|
-
</
|
|
524
|
-
<
|
|
476
|
+
</FieldContent>
|
|
477
|
+
<FieldError errors={[fieldState.error]} />
|
|
525
478
|
|
|
526
|
-
{showSelected
|
|
479
|
+
{showSelected && selected.length > 0 ? (
|
|
480
|
+
<div className="flex flex-wrap gap-2 mt-2">
|
|
527
481
|
{selected.map(value => {
|
|
528
|
-
const
|
|
529
|
-
options
|
|
530
|
-
.flatMap(o => ("options" in o ? o.options : o))
|
|
531
|
-
.find(o => o.value === value)?.label ?? value;
|
|
482
|
+
const badgeLabel =
|
|
483
|
+
options.flatMap(o => ("options" in o ? o.options : o)).find(o => o.value === value)?.label ?? value;
|
|
532
484
|
return (
|
|
533
485
|
<Badge
|
|
534
486
|
onClick={() => !disabled && toggleOption(value)}
|
|
535
487
|
key={value}
|
|
536
|
-
aria-disabled
|
|
488
|
+
aria-disabled={disabled}
|
|
537
489
|
variant="secondary"
|
|
538
490
|
className={cn("px-2 py-1", !disabled && "cursor-pointer")}
|
|
539
491
|
>
|
|
540
|
-
{
|
|
492
|
+
{badgeLabel}
|
|
541
493
|
{!disabled && <X className="ml-1 h-3 w-3 cursor-pointer" />}
|
|
542
494
|
</Badge>
|
|
543
495
|
);
|
|
544
496
|
})}
|
|
545
|
-
</div>
|
|
546
|
-
|
|
497
|
+
</div>
|
|
498
|
+
) : null}
|
|
499
|
+
</Field>
|
|
547
500
|
);
|
|
548
501
|
}}
|
|
549
502
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cn } from
|
|
1
|
+
import { cn } from "@repo/ui/lib/utils";
|
|
2
2
|
|
|
3
3
|
export type GridProps = {
|
|
4
4
|
children: React.ReactNode;
|
|
@@ -10,9 +10,9 @@ const Grid = (props: GridProps) => {
|
|
|
10
10
|
return (
|
|
11
11
|
<div
|
|
12
12
|
className={cn(
|
|
13
|
-
|
|
14
|
-
props.grow ?
|
|
15
|
-
props.className
|
|
13
|
+
"grid sm:grid-cols-12 gap-2 grid-cols-1",
|
|
14
|
+
props.grow ? "min-h-[calc(100vh-60px)] py-2" : "",
|
|
15
|
+
props.className
|
|
16
16
|
)}
|
|
17
17
|
>
|
|
18
18
|
{props.children}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { ClassNameValue } from "tailwind-merge";
|
|
3
3
|
|
|
4
|
-
import { cn } from "
|
|
4
|
+
import { cn } from "@repo/ui/lib/utils";
|
|
5
5
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
|
|
6
6
|
|
|
7
7
|
const HoverTool = ({
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { GalleryHorizontal } from
|
|
2
|
-
import { useRef } from
|
|
3
|
-
import { type ChangeEvent, useState } from
|
|
1
|
+
import { GalleryHorizontal } from "lucide-react";
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
import { type ChangeEvent, useState } from "react";
|
|
4
4
|
|
|
5
|
-
import { Button } from
|
|
5
|
+
import { Button } from "@repo/ui/components/ui/button";
|
|
6
6
|
import {
|
|
7
7
|
Carousel,
|
|
8
8
|
CarouselContent,
|
|
9
9
|
CarouselItem,
|
|
10
10
|
CarouselNext,
|
|
11
11
|
CarouselPrevious,
|
|
12
|
-
} from
|
|
12
|
+
} from "@repo/ui/components/ui/carousel";
|
|
13
|
+
import { cn } from "@repo/ui/lib/utils.js";
|
|
13
14
|
|
|
14
|
-
import { cn } from '../lib/utils.js';
|
|
15
15
|
const ImagePicker = ({
|
|
16
16
|
onChange,
|
|
17
17
|
defaultValue,
|
|
@@ -25,20 +25,18 @@ const ImagePicker = ({
|
|
|
25
25
|
}) => {
|
|
26
26
|
const getDefaultImage = () => {
|
|
27
27
|
try {
|
|
28
|
-
if (!defaultValue) return
|
|
28
|
+
if (!defaultValue) return "";
|
|
29
29
|
return URL.createObjectURL(defaultValue);
|
|
30
30
|
} catch (error) {
|
|
31
|
-
return
|
|
31
|
+
return "";
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
|
-
const [selectedImage, setSelectedImage] = useState<string[]>(
|
|
35
|
-
getDefaultImage() ? [getDefaultImage()] : [],
|
|
36
|
-
);
|
|
34
|
+
const [selectedImage, setSelectedImage] = useState<string[]>(getDefaultImage() ? [getDefaultImage()] : []);
|
|
37
35
|
|
|
38
36
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
|
39
37
|
const handleImageChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
40
38
|
if (event.target.files?.[0]) {
|
|
41
|
-
setSelectedImage(Array.from(event.target.files).map(
|
|
39
|
+
setSelectedImage(Array.from(event.target.files).map(file => URL.createObjectURL(file)));
|
|
42
40
|
const file = event.target.files;
|
|
43
41
|
onChange?.(file);
|
|
44
42
|
}
|
|
@@ -46,17 +44,17 @@ const ImagePicker = ({
|
|
|
46
44
|
return (
|
|
47
45
|
<div>
|
|
48
46
|
<div className="flex items-start w-full aspect-video flex-col gap-2">
|
|
49
|
-
<
|
|
47
|
+
<Button
|
|
50
48
|
onClick={() => fileInputRef.current?.click()}
|
|
51
49
|
className={cn(
|
|
52
|
-
|
|
53
|
-
className
|
|
50
|
+
"border-dashed grid place-content-center min-w-full aspect-video border border-gray-300 rounded-md overflow-hidden",
|
|
51
|
+
className
|
|
54
52
|
)}
|
|
55
53
|
>
|
|
56
54
|
{selectedImage.length !== 0 ? (
|
|
57
55
|
<Carousel>
|
|
58
56
|
<CarouselContent>
|
|
59
|
-
{selectedImage.map(
|
|
57
|
+
{selectedImage.map(image => (
|
|
60
58
|
<CarouselItem key={image}>
|
|
61
59
|
<img
|
|
62
60
|
alt={image}
|
|
@@ -87,19 +85,19 @@ const ImagePicker = ({
|
|
|
87
85
|
<GalleryHorizontal className="text-gray-500 drop-shadow-lg " size={40} />
|
|
88
86
|
</div>
|
|
89
87
|
)}
|
|
90
|
-
</
|
|
88
|
+
</Button>
|
|
91
89
|
<Button
|
|
92
90
|
type="button"
|
|
93
91
|
className="px-8 border-dotted"
|
|
94
92
|
disabled={disabled}
|
|
95
|
-
onClick={
|
|
93
|
+
onClick={e => {
|
|
96
94
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
97
95
|
selectedImage.length === 0 ? fileInputRef.current?.click() : setSelectedImage([]);
|
|
98
96
|
onChange?.(null);
|
|
99
97
|
}}
|
|
100
|
-
variant={selectedImage.length > 0 ?
|
|
98
|
+
variant={selectedImage.length > 0 ? "destructive" : "outline"}
|
|
101
99
|
>
|
|
102
|
-
{selectedImage.length === 0 ?
|
|
100
|
+
{selectedImage.length === 0 ? "Upload image" : "Remove image"}
|
|
103
101
|
</Button>
|
|
104
102
|
</div>
|
|
105
103
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Loader, Scroll } from
|
|
2
|
-
import type { ReactNode } from
|
|
1
|
+
import { Loader, Scroll } from "lucide-react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
3
|
|
|
4
|
-
import { cn } from
|
|
4
|
+
import { cn } from "@repo/ui/lib/utils";
|
|
5
5
|
|
|
6
6
|
type NoContentProps = {
|
|
7
7
|
icon?: ReactNode;
|
|
@@ -12,26 +12,16 @@ type NoContentProps = {
|
|
|
12
12
|
export const NoContent = (props: NoContentProps) => {
|
|
13
13
|
if (props.loading) {
|
|
14
14
|
return (
|
|
15
|
-
<div
|
|
16
|
-
className={cn(
|
|
17
|
-
'h-full w-full flex flex-col gap-2 justify-center items-center',
|
|
18
|
-
props.className ?? '',
|
|
19
|
-
)}
|
|
20
|
-
>
|
|
15
|
+
<div className={cn("h-full w-full flex flex-col gap-2 justify-center items-center", props.className ?? "")}>
|
|
21
16
|
<Loader className="animate-spin" />
|
|
22
17
|
<p className="text-sm text-muted-foreground">loading</p>
|
|
23
18
|
</div>
|
|
24
19
|
);
|
|
25
20
|
}
|
|
26
21
|
return (
|
|
27
|
-
<div
|
|
28
|
-
className={cn(
|
|
29
|
-
'h-full w-full flex text-sm flex-col gap-2 justify-center items-center',
|
|
30
|
-
props.className ?? '',
|
|
31
|
-
)}
|
|
32
|
-
>
|
|
22
|
+
<div className={cn("h-full w-full flex text-sm flex-col gap-2 justify-center items-center", props.className ?? "")}>
|
|
33
23
|
{props.icon ?? <Scroll />}
|
|
34
|
-
<p className=" text-muted-foreground">{props.label ??
|
|
24
|
+
<p className=" text-muted-foreground">{props.label ?? "No Content"}</p>
|
|
35
25
|
</div>
|
|
36
26
|
);
|
|
37
27
|
};
|