This commit is contained in:
rizky 2024-08-08 01:35:45 -07:00
parent 15e1e983a5
commit 5022096c06
23 changed files with 383 additions and 93 deletions

View File

@ -41,6 +41,7 @@ export const BarChart: FC<{
datasetIdKey="id"
options={{
responsive: true,
maintainAspectRatio: false,
plugins:
legend === "none"
? {

View File

@ -43,6 +43,7 @@ interface Props {
onClickNext: () => void;
changeMonth: (month: number) => void;
changeYear: (year: number) => void;
mode?: "monthly" | "daily";
}
const Calendar: React.FC<Props> = ({
@ -53,6 +54,7 @@ const Calendar: React.FC<Props> = ({
onClickNext,
changeMonth,
changeYear,
mode = "daily",
}) => {
// Contexts
const {
@ -73,6 +75,12 @@ const Calendar: React.FC<Props> = ({
const [showMonths, setShowMonths] = useState(false);
const [showYears, setShowYears] = useState(false);
const [year, setYear] = useState(date.year());
useEffect(() => {
if (mode === "monthly") {
setShowMonths(true);
hideYears();
}
}, []);
// Functions
const previous = useCallback(() => {
return getLastDaysInMonth(
@ -104,7 +112,12 @@ const Calendar: React.FC<Props> = ({
(month: number) => {
setTimeout(() => {
changeMonth(month);
setShowMonths(!showMonths);
if (mode === "daily") {
setShowMonths(!showMonths);
} else {
hideDatepicker();
clickDay(1,month + 1, date.year() );
}
}, 250);
},
[changeMonth, showMonths]
@ -115,6 +128,10 @@ const Calendar: React.FC<Props> = ({
setTimeout(() => {
changeYear(year);
setShowYears(!showYears);
if (mode === "monthly") {
setShowMonths(true);
clickDay(1,date.month() + 1, year );
}
}, 250);
},
[changeYear, showYears]
@ -125,7 +142,6 @@ const Calendar: React.FC<Props> = ({
const fullDay = `${year}-${month}-${day}`;
let newStart;
let newEnd = null;
function chosePeriod(start: string, end: string) {
const ipt = input?.current;
changeDatepickerValue(

View File

@ -51,6 +51,7 @@ const Datepicker: React.FC<DatepickerType> = ({
startWeekOn = "sun",
classNames = undefined,
popoverDirection = undefined,
mode="daily"
}) => {
const local = useLocal({ open: false });
// Ref
@ -95,6 +96,7 @@ const Datepicker: React.FC<DatepickerType> = ({
if (newDate.isSame(reformatDate) || newDate.isAfter(reformatDate)) {
setSecondDate(nextMonth(date));
}
console.log(date)
setFirstDate(date);
},
[secondDate]
@ -110,6 +112,7 @@ const Datepicker: React.FC<DatepickerType> = ({
const changeFirstMonth = useCallback(
(month: number) => {
console.log("HALOOO")
firstGotoDate(
dayjs(`${firstDate.year()}-${month < 10 ? "0" : ""}${month}-01`)
);
@ -148,6 +151,7 @@ const Datepicker: React.FC<DatepickerType> = ({
const changeSecondMonth = useCallback(
(month: number) => {
console.log("ALOO")
secondGotoDate(
dayjs(`${secondDate.year()}-${month < 10 ? "0" : ""}${month}-01`)
);
@ -323,8 +327,8 @@ const Datepicker: React.FC<DatepickerType> = ({
return typeof containerClassName === "function"
? containerClassName(defaultContainerClassName)
: typeof containerClassName === "string" && containerClassName !== ""
? containerClassName
: defaultContainerClassName;
? containerClassName
: defaultContainerClassName;
}, [containerClassName]);
return (
@ -339,7 +343,9 @@ const Datepicker: React.FC<DatepickerType> = ({
open={local.open}
content={
<div
className={cx("c-text-sm 2xl:c-text-sm")}
className={cx(
"c-text-sm 2xl:c-text-sm",
)}
ref={calendarContainerRef}
>
<div className="c-flex c-flex-col lg:c-flex-row c-py-1">
@ -356,6 +362,7 @@ const Datepicker: React.FC<DatepickerType> = ({
onClickNext={nextMonthFirst}
changeMonth={changeFirstMonth}
changeYear={changeFirstYear}
mode={mode}
minDate={minDate}
maxDate={maxDate}
/>
@ -372,6 +379,7 @@ const Datepicker: React.FC<DatepickerType> = ({
onClickNext={nextMonthSecond}
changeMonth={changeSecondMonth}
changeYear={changeSecondYear}
mode={mode}
minDate={minDate}
maxDate={maxDate}
/>

View File

@ -82,6 +82,7 @@ export interface DatepickerType {
disabledDates?: DateRangeType[] | null;
startWeekOn?: string | null;
popoverDirection?: PopoverDirectionType;
mode?: "daily" | "monthly"
}
export type ColorKeys = (typeof COLORS)[number]; // "blue" | "orange"

View File

@ -137,6 +137,7 @@ function PopoverArrow() {
top: arrowY != null ? `${arrowY}px` : "",
[staticSide]: "-4px",
transform: "rotate(45deg)",
cursor: "pointer"
}}
className={cx(
"arrow",

View File

@ -3,14 +3,16 @@ import { BaseForm } from "../form/base/BaseForm";
import { FilterLocal } from "./utils/types";
import { useLocal } from "lib/utils/use-local";
import { getFilter } from "./utils/get-filter";
import { FMLocal } from "lib/exports";
export const FilterContent: FC<{
mode: string;
filter: FilterLocal;
onSubmit?: (form: FMLocal | null) => Promise<any>;
PassProp: any;
child: any;
_item: PrasiItem;
}> = ({ mode, filter, PassProp, child, _item }) => {
}> = ({ mode, filter, PassProp, child, _item, onSubmit }) => {
const internal = useLocal({});
return (
<div
@ -97,9 +99,18 @@ export const FilterContent: FC<{
>
<BaseForm
data={filter.data}
on_submit={(form) => {
const f = getFilter(filter.name);
on_submit={async (form) => {
if (typeof onSubmit === "function" && mode === "raw") {
const data = await onSubmit(form.fm);
if(typeof form.fm?.data === "object"){
form.fm.data = {
...form.fm.data,
_where: data
}
}
}
const f = getFilter(filter.name);
if (f) {
for (const list of Object.values(f.list.ref)) {
list.reload();
@ -113,7 +124,9 @@ export const FilterContent: FC<{
return (
<>
{!!(PassProp && child) && (
<PassProp filter={filter}>{child}</PassProp>
<PassProp filter={filter} fm={form.fm}>
{child}
</PassProp>
)}
</>
);

View File

@ -29,7 +29,7 @@ export const FilterField: FC<{
internal.render_timeout = setTimeout(() => {
filter_window.prasiContext.render();
}, 500);
}, [filter.form?.data[name]]);
}, [filter.form]);
let show_modifier = filter.mode !== "inline";

View File

@ -1,7 +1,7 @@
import { useLocal } from "@/utils/use-local";
import { FC, ReactNode } from "react";
import { createPortal } from "react-dom";
import { GenField } from "../form/typings";
import { FMLocal, GenField } from "../form/typings";
import { FilterContent } from "./FilterContent";
import { getFilter } from "./utils/get-filter";
import { default_filter_local } from "./utils/types";
@ -16,6 +16,7 @@ type FilterProps = {
mode: FilterMode;
children?: ReactNode;
onClose?: () => void;
onSubmit?: (fm: FMLocal | null) => Promise<any>;
PassProp: any;
child: any;
_item: PrasiItem;
@ -31,6 +32,7 @@ export const MasterFilter: FC<FilterProps> = ({
child,
onClose,
_item,
onSubmit,
}): ReactNode => {
const filter = useLocal({ ...default_filter_local });
filter.name = name;
@ -74,6 +76,7 @@ export const MasterFilter: FC<FilterProps> = ({
)}
>
<FilterContent
onSubmit={onSubmit}
PassProp={PassProp}
child={child}
mode={mode}
@ -90,6 +93,7 @@ export const MasterFilter: FC<FilterProps> = ({
return (
<>
<FilterContent
onSubmit={onSubmit}
PassProp={PassProp}
_item={_item}
child={child}

View File

@ -5,17 +5,24 @@ import { softDeleteFilter } from "./soft-delete-filter";
export const filterWhere = (filter_name: string, p: any) => {
const f = getFilter(filter_name);
let where: any = {};
if (f) {
let fields: GFCol[] = [];
//
if (p.gen__fields) {
fields = parseGenField(p.gen__fields);
}
for (const pf of Object.values(f.filter.ref)) {
const w = parseSingleFilter(pf, fields);
for (const [k, v] of Object.entries(w)) {
where[k] = v;
if (pf.mode === "raw") {
const data = pf.data?._where ? pf.data?._where : pf.data
for (const [k, v] of Object.entries(data)) {
where[k] = v;
}
} else {
const w = parseSingleFilter(pf, fields);
for (const [k, v] of Object.entries(w)) {
where[k] = v;
}
}
}
}
@ -27,6 +34,6 @@ export const filterWhere = (filter_name: string, p: any) => {
type: p.sft__type,
});
}
console.log({where})
return where;
};

View File

@ -61,9 +61,9 @@ export const BaseForm = <T extends Record<string, any>>(
return prop;
};
form.createFm = () => {
form.createFm = useCallback(() => {
if (form.fm) {
form.fm.data = form.data;
form.fm.data = data;
return form.fm;
}
let size = "full";
@ -72,7 +72,7 @@ export const BaseForm = <T extends Record<string, any>>(
size = "half";
}
form.fm = {
data: form.data,
data: data,
props: { label_mode: "vertical" },
error: {
get: () => {
@ -84,7 +84,7 @@ export const BaseForm = <T extends Record<string, any>>(
render: form.render,
} as any;
return form.fm as any;
};
}, [data]);
form.fieldProps = (arg) => {
return {
@ -95,8 +95,8 @@ export const BaseForm = <T extends Record<string, any>>(
};
useEffect(() => {
form.data = data;
form.render();
// form.data = data;
// form.render();
if (form.internal.width === 0) {
setTimeout(() => {
@ -142,7 +142,9 @@ export const BaseForm = <T extends Record<string, any>>(
form.render();
}, 50);
}
if (!form.fm) {
form.fm = form.createFm();
}
return (
<form
onSubmit={(e) => {

View File

@ -3,7 +3,7 @@ import { FMLocal, FieldLocal, FieldProp } from "../typings";
export const default_base_form_local = {
status: "init" as "init" | "submitting" | "ready",
data: {} as any,
// data: {} as any,
internal: {
width: 0,
init_render: 0,
@ -23,7 +23,7 @@ type CreateFieldArg = {
};
export type BaseFormLocal<T> = Omit<typeof default_base_form_local, "data"> & {
data: T;
// data: T;
createArg: (arg: CreateFieldArg) => FieldProp;
createField: (arg: CreateFieldArg) => FieldLocal;
createFm: () => FMLocal;

View File

@ -13,7 +13,7 @@ export const Field: FC<FieldProp> = (arg) => {
const { fm } = arg;
const field = useField(arg);
const name = field.name;
const local = useLocal({ prev_val: fm.data[name] });
const local = useLocal({ prev_val: fm.data?.[name] });
const w = field.width;
@ -29,14 +29,29 @@ export const Field: FC<FieldProp> = (arg) => {
if (arg.on_change) {
arg.on_change({ value: fm.data[name], name, fm });
}
if(!fm.events){
fm.events = {
on_change(name, new_value) {
},
}
}
fm.events.on_change(name, fm.data[name]);
fm.render();
}
}, [fm.data[name]]);
useEffect(() => {
if (typeof arg.on_init === "function") {
arg.on_init({ name, field });
}
}, [field]);
if (field.status === "init" && !isEditor) return null;
const errors = fm.error.get(name);
let errors = fm.error.get(name);
if(field.error){
errors = [field.error]
}
const props = { ...arg.props };
let editorClassName = "";
@ -45,6 +60,8 @@ export const Field: FC<FieldProp> = (arg) => {
props.className.split(" ").find((e: string) => e.startsWith("s-")) || "";
}
const disabled =
typeof field.disabled === "function" ? field.disabled() : field.disabled;
if (field.hidden) return <></>;
return (
@ -72,7 +89,7 @@ export const Field: FC<FieldProp> = (arg) => {
"c-flex-col c-space-y-1",
css`
.field-outer {
border: 1px solid ${field.disabled ? "#ececeb" : "#cecece"};
border: 1px solid ${disabled ? "#ececeb" : "#cecece"};
&.focused {
border: 1px solid #1c4ed8;
@ -98,7 +115,7 @@ export const Field: FC<FieldProp> = (arg) => {
{field.desc}
</div>
)}
{errors.length > 0 && (
{errors.length ? (
<div
className={cx(
"field-error c-p-2 c-text-xs c-text-red-600",
@ -109,7 +126,7 @@ export const Field: FC<FieldProp> = (arg) => {
return <div>{err}</div>;
})}
</div>
)}
) : <></>}
</div>
</LabelDiv>
);

View File

@ -6,13 +6,14 @@ export const Label: FC<{ field: FieldLocal; fm: FMLocal }> = ({
fm,
}) => {
const errors = fm.error.get(field.name);
const disabled =
typeof field.disabled === "function" ? field.disabled() : field.disabled;
return (
<div className={cx("label c-text-sm c-flex c-items-center", "c-mt-3")}>
<span className={cx(errors.length > 0 && `c-text-red-600`)}>
{field.label}
</span>
{field.required && !field.disabled && (
{field.required && !disabled && (
<span className="c-text-red-600 c-mb-2 c-ml-1">
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@ -154,15 +154,10 @@ export const TableEdit: FC<{
}
return (
<>
<div
className={cx(
`c-w-full c-h-full c-flex c-flex-col`,
css`
.rdg {
overflow-y: hidden !important;
height: var(--rdg-scroll-height) !important;
}
.rdg-cell > div {
flex-direction: row;
align-items: center;
@ -172,9 +167,6 @@ export const TableEdit: FC<{
padding-top: 0px;
}
}
.field-error {
display: none;
}
.rdg-header-row {
border-top-right-radius: 5px;
border-top-left-radius: 5px;
@ -192,6 +184,7 @@ export const TableEdit: FC<{
className={cx(
"c-table-auto",
css`
height: 1px;
border-collapse: collapse;
table-layout: auto; /* Kolom akan menyesuaikan konten */
`
@ -241,7 +234,7 @@ export const TableEdit: FC<{
{columns.map((header) => {
return (
<td>
<div className="c-flex c-flex-row c-py-2 c-w-full">
<div className="c-flex c-flex-row c-py-2 c-w-full c-h-full">
{header.renderCell({
props: {
row: row,

View File

@ -33,6 +33,24 @@ export const TypeDropdown: FC<{
data: e.data,
};
});
let v = typeof arg.opt_get_value === "function"
? arg.opt_get_value({
fm,
name: field.name,
options: local.options,
type: field.type,
})
: fm.data[field.name];
let f = list.find((ex) => ex.value === v);
if(!f){
arg.opt_set_value({
fm,
name: field.name,
type: field.type,
options: local.options,
selected: [],
});
}
local.options = list;
} else {
local.options = res;

View File

@ -28,7 +28,8 @@ export type PropTypeInput = {
| "file"
| "search"
| "password"
| "import";
| "import"
| "monthly";
placeholder?: string;
onFocus?: (e: FocusEvent<HTMLDivElement>) => void;
onBlur?: (e: FocusEvent<HTMLDivElement>) => void;
@ -168,7 +169,7 @@ export const FieldTypeInput: FC<{
case "upload":
return (
<FieldUpload
arg={arg}
arg={arg}
field={field}
fm={fm}
prop={prop}
@ -178,7 +179,7 @@ export const FieldTypeInput: FC<{
case "import":
return (
<FieldUpload
arg={arg}
arg={arg}
field={field}
fm={fm}
prop={prop}
@ -199,11 +200,34 @@ export const FieldTypeInput: FC<{
value={{ startDate: value, endDate: value }}
disabled={disabled}
displayFormat="DD MMM YYYY"
mode={"daily"}
maxDate={field.max_date instanceof Date ? field.max_date : null}
minDate={field.min_date instanceof Date ? field.min_date : null}
asSingle={true}
useRange={false}
onChange={(value) => {
console.log({ value });
fm.data[field.name] = value?.startDate
? new Date(value?.startDate)
: null;
renderOnChange();
}}
/>
);
}
case "monthly": {
return (
<Datepicker
value={{ startDate: value, endDate: value }}
disabled={disabled}
displayFormat="MMM YYYY"
mode={"monthly"}
maxDate={field.max_date instanceof Date ? field.max_date : null}
minDate={field.min_date instanceof Date ? field.min_date : null}
asSingle={true}
useRange={false}
onChange={(value) => {
console.log({ value });
fm.data[field.name] = value?.startDate
? new Date(value?.startDate)
: null;

View File

@ -107,6 +107,10 @@ export type FieldProp = {
current: any;
options: { value: string; label: string; item?: any }[];
}) => boolean;
on_init: (arg: {
field: any,
name: string
}) => void;
pk: string;
sub_type: string;
placeholder: string;
@ -188,6 +192,8 @@ export type FieldInternal<T extends FieldProp["type"]> = {
prop?: any;
max_date?: FieldProp["max_date"];
min_date?: FieldProp["min_date"];
error?: any;
table_fields?: any[]
};
export type FieldLocal = FieldInternal<any> & {
render: () => void;

View File

@ -16,35 +16,33 @@ export const useField = (
input: {},
ref: null as any,
} as any);
const ref = useRef(null as any);
const ref = useRef(null as any)
field.ref = ref;
const name = typeof arg.name === "string" ? arg.name : arg.name();
const label = typeof arg.label === "string" ? arg.label : arg.label();
const required =
typeof arg.required === "string" ? arg.required : arg.required();
const update_field = {
name: name.replace(/\s*/gi, ""),
label: label,
type: arg.type,
desc: arg.desc,
prefix: arg.prefix,
suffix: arg.suffix,
width: arg.width,
custom: arg.custom,
required: required === "y",
required_msg: arg.required_msg,
disabled: typeof arg.disabled === "function" ? arg.disabled : arg.disabled === "y",
on_change: arg.on_change,
max_date: arg.max_date,
min_date: arg.min_date,
table_fields: []
};
if (field.status === "init" || isEditor) {
for (const [k, v] of Object.entries({
name: name.replace(/\s*/gi, ""),
label: label,
type: arg.type,
desc: arg.desc,
prefix: arg.prefix,
suffix: arg.suffix,
width: arg.width,
custom: arg.custom,
required: required === "y",
required_msg: arg.required_msg,
disabled:
typeof arg.disabled === "function"
? arg.disabled
: arg.disabled === "y",
on_change: arg.on_change,
max_date: arg.max_date,
min_date: arg.min_date,
options: {},
reload_options: () => {},
})) {
for (const [k, v] of Object.entries(update_field)) {
(field as any)[k] = v;
}
}
@ -54,6 +52,9 @@ export const useField = (
useEffect(() => {
if (field.status === "init" || !fm.fields[name]) {
field.status = "ready";
if(!fm.fields){
fm.fields = {}
}
fm.fields[name] = field;
field.render();
}

View File

@ -183,7 +183,6 @@ export const TableList: FC<TableListProp> = ({
let should_set = true;
const gf = JSON.stringify(gen_fields);
const fields = fields_map.get(gf);
if (fields) {
const rel = fields?.find((e) => e.name === columnKey);
if (rel && rel.checked) {
@ -196,9 +195,7 @@ export const TableList: FC<TableListProp> = ({
},
};
} else {
const field = rel.checked.find(
(e) => !e.is_pk && !e.relation
);
const field = rel.checked.find((e) => !e.is_pk);
if (field) {
local.sort.orderBy = {
[columnKey]: {

46
comps/ui/scroll-area.tsx Executable file
View File

@ -0,0 +1,46 @@
"use client"
import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import { cn } from "@/utils"
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("c-relative c-overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="c-h-full c-w-full c-rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"c-flex c-touch-none c-select-none c-transition-colors",
orientation === "vertical" &&
"c-h-full c-w-2.5 c-border-l c-border-l-transparent c-p-[1px]",
orientation === "horizontal" &&
"c-h-2.5 c-flex-col c-border-t c-border-t-transparent c-p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="c-relative c-flex-1 c-rounded-full c-bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
export { ScrollArea, ScrollBar }

134
comps/ui/sheet.tsx Executable file
View File

@ -0,0 +1,134 @@
"use client";
import * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"c-fixed c-inset-0 c-z-50 c-bg-black/80 data-[state=open]:c-animate-in data-[state=closed]:c-animate-out data-[state=closed]:c-fade-out-0 data-[state=open]:c-fade-in-0",
className
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"c-fixed c-z-50 c-gap-4 c-bg-background c-p-6 c-shadow-lg c-transition c-ease-in-out data-[state=closed]:c-duration-300 data-[state=open]:c-duration-500 data-[state=open]:c-animate-in data-[state=closed]:c-animate-out",
{
variants: {
side: {
top: "c-inset-x-0 c-top-0 c-border-b data-[state=closed]:c-slide-out-to-top data-[state=open]:c-slide-in-from-top",
bottom:
"c-inset-x-0 c-bottom-0 c-border-t data-[state=closed]:c-slide-out-to-bottom data-[state=open]:c-slide-in-from-bottom",
left: "c-inset-y-0 c-left-0 c-h-full c-w-3/4 c-border-r data-[state=closed]:c-slide-out-to-left data-[state=open]:c-slide-in-from-left sm:c-max-w-sm",
right:
"c-inset-y-0 c-right-0 c-h-full c-w-3/4 c-border-l data-[state=closed]:c-slide-out-to-right data-[state=open]:c-slide-in-from-right sm:c-max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"c-flex c-flex-col c-space-y-2 c-text-center sm:c-text-left",
className
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"c-flex c-flex-col-reverse sm:c-flex-row sm:c-justify-end sm:c-space-x-2",
className
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("c-text-lg c-font-semibold c-text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("c-text-sm c-text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};

View File

@ -1,10 +1,10 @@
export { FieldLoading } from "@/comps/ui/field-loading";
export { fetchLinkParams } from "./comps/form/field/type/TypeLink";
export { prasi_gen } from "./gen/prasi_gen";
export { guessLabel } from "./utils/guess-label";
import { lazify, lazifyMany } from "@/utils/lazify";
import __get from "lodash.get";
import { sum } from "./utils/sum";
export { guessLabel } from "./utils/guess-label";
export { fetchLinkParams } from "./comps/form/field/type/TypeLink";
export { prasi_gen } from "./gen/prasi_gen";
export const _sum = sum;
export const _get = __get;
@ -80,8 +80,8 @@ export const HeaderProfile = lazify(
);
/** charts */
export { PieChart } from "@/comps/charts/pie";
export { BarChart } from "@/comps/charts/bar";
export { PieChart } from "@/comps/charts/pie";
// export { LineChart } from "@/comps/charts/line";
/** Generator */
@ -98,11 +98,9 @@ export { generateForm } from "@/comps/form/gen/gen-form";
export { validate as validateField } from "@/comps/form/utils/validate";
export { sortTree, treePrefix } from "@/comps/list/utils/sort-tree";
export { getFilter } from "@/comps/filter/utils/get-filter";
export {
FMLocal,
FieldTypeCustom,
fieldType,
formType,
fieldType, FieldTypeCustom, FMLocal, formType
} from "@/comps/form/typings";
export { TableListType } from "@/comps/list/utils/typings";
export { generateTableList as generateTableList } from "@/comps/md/gen/gen-table-list";
@ -112,17 +110,15 @@ export { Button, FloatButton } from "@/comps/ui/button";
export { FormatValue } from "@/utils/format-value";
export { GetValue } from "@/utils/get-value";
export { password } from "@/utils/password";
export { prasi_events, call_prasi_events } from "lib/utils/prasi-events";
export { getFilter } from "@/comps/filter/utils/get-filter";
export { call_prasi_events, prasi_events } from "lib/utils/prasi-events";
/** Session */
export { Login } from "@/preset/login/Login";
export { generateLogin } from "@/preset/login/utils/generate";
export { logout } from "@/preset/login/utils/logout";
export {
RG,
UserSession,
registerSession,
registerSession, RG,
UserSession
} from "@/preset/login/utils/register";
export { Card } from "@/comps/custom/Card";
@ -143,12 +139,15 @@ export { PanelTab } from "@/comps/tab/parts/PanelTab";
export { Popup } from "@/comps/popup/PopUp";
export { Detail } from "@/comps/custom/Detail";
export * from "@/comps/ui/input";
export { ButtonUpload } from "@/preset/profile/ButtonUpload";
export { Profile } from "@/preset/profile/Profile";
export { generateProfile } from "@/preset/profile/utils/generate";
export { formatTime, longDate, shortDate, timeAgo } from "@/utils/date";
export { getPathname, getBasename } from "@/utils/pathname";
export * from "@/comps/ui/input";
export { getBasename, getPathname } from "@/utils/pathname";
export { Flow } from "@/comps/ui/flow";
// format money
export { formatMoney } from "@/comps/form/field/type/TypeMoney";
export { ScrollArea } from "@/comps/ui/scroll-area";

View File

@ -49,7 +49,7 @@ export const FormatValue: FC<{
if (mode === "money") {
if (isEmptyString(value)) return "-";
return formatMoney(Number(value) || 0);
return formatMoney(ceil_comma(Number(value) || 0));
} else if (mode === "datetime") {
if (!value || isEmptyString(value)) return "-";
try {
@ -120,7 +120,7 @@ export const FormatValue: FC<{
}
} else if (["float"].includes(field?.type as string)) {
if (!value || isEmptyString(value)) return "-";
return formatMoney(Number(value) || 0);
return formatMoney(ceil_comma(Number(value) || 0));
}
}
@ -169,12 +169,13 @@ const timeAgo = (date: any) => {
const daysPast = Math.floor(secondsPast / 86400);
return `${daysPast} days ago`;
} else {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
return `${day}-${month}-${year}`;
return formatDate(dayjs(date), "DD MMMM YYYY");
}
} catch (e) {
return null;
}
};
const ceil_comma = (number: number) => {
if (!number) return 0;
return Math.ceil(number * 100) / 100;
};