checkpoint
This commit is contained in:
parent
fff47ee40a
commit
61845dc62b
|
|
@ -27,6 +27,7 @@ interface Props {
|
|||
onClickDay: (day: number) => void;
|
||||
onClickNextDays: (day: number) => void;
|
||||
onIcon?: (day: number, date: Date) => any;
|
||||
style?: string;
|
||||
}
|
||||
|
||||
const Days: React.FC<Props> = ({
|
||||
|
|
@ -35,6 +36,7 @@ const Days: React.FC<Props> = ({
|
|||
onClickDay,
|
||||
onClickNextDays,
|
||||
onIcon,
|
||||
style,
|
||||
}) => {
|
||||
// Contexts
|
||||
const {
|
||||
|
|
@ -241,13 +243,18 @@ const Days: React.FC<Props> = ({
|
|||
|
||||
const buttonClass = useCallback(
|
||||
(day: number, type: "current" | "next" | "previous") => {
|
||||
const baseClass =
|
||||
"c-flex c-items-center c-justify-center c-w-12 c-h-12 lg:c-w-10 lg:c-h-10 c-relative";
|
||||
let baseClass = `calender-day c-flex c-items-center c-justify-center ${
|
||||
style === "google"
|
||||
? " c-w-6 c-h-6 c-m-1"
|
||||
: "c-w-12 c-h-12 lg:c-w-10 lg:c-h-10"
|
||||
} c-relative`;
|
||||
if (type === "current") {
|
||||
return cn(
|
||||
baseClass,
|
||||
!activeDateData(day).active
|
||||
? hoverClassByDay(day)
|
||||
: style === "google"
|
||||
? ""
|
||||
: activeDateData(day).className,
|
||||
isDateDisabled(day, type) && "c-text-gray-400 c-cursor-not-allowed"
|
||||
);
|
||||
|
|
@ -403,62 +410,171 @@ const Days: React.FC<Props> = ({
|
|||
return typeof onIcon === "function" ? onIcon(day, res) : null;
|
||||
};
|
||||
return (
|
||||
<div className="c-grid c-grid-cols-7 c-gap-y-0.5 c-my-1">
|
||||
<div
|
||||
className={cx(
|
||||
"calender-days c-grid c-grid-cols-7 c-gap-y-0.5 c-my-1",
|
||||
css`
|
||||
grid-template-columns: repeat(
|
||||
auto-fit,
|
||||
minmax(0px, 1fr)
|
||||
); /* Grid fleksibel */
|
||||
|
||||
.calender-grid {
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
`
|
||||
)}
|
||||
>
|
||||
{calendarData.days.previous.map((item, index) => (
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "previous")}
|
||||
className={`${buttonClass(item, "previous")}`}
|
||||
onClick={() => handleClickDay(item, "previous")}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "previous");
|
||||
<div
|
||||
className={cx(
|
||||
"calender-grid c-flex c-flex-row",
|
||||
style === "google" ? "hover:c-bg-gray-100 c-cursor-pointer" : ""
|
||||
)}
|
||||
onClick={() => {
|
||||
if (style === "google") handleClickDay(item, "previous");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">
|
||||
{item}
|
||||
{load_marker(item, "previous")}
|
||||
</span>
|
||||
</button>
|
||||
<div className="c-flex c-flex-col c-flex-grow calender-day-wrap">
|
||||
{style === "google" ? (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "previous")}
|
||||
className={`${buttonClass(item, "previous")}`}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "previous");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">{item}</span>
|
||||
</button>
|
||||
<div>{load_marker(item, "previous")}</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "previous")}
|
||||
className={`${buttonClass(item, "previous")}`}
|
||||
onClick={() => handleClickDay(item, "previous")}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "previous");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">
|
||||
{item}
|
||||
{load_marker(item, "previous")}
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{calendarData.days.current.map((item, index) => (
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "current")}
|
||||
<div
|
||||
className={cx(
|
||||
`${buttonClass(item, "current")}`,
|
||||
item === 1 && "highlight"
|
||||
"calender-grid c-flex c-flex-row",
|
||||
style === "google"
|
||||
? activeDateData(item).active
|
||||
? "c-bg-blue-200/75 c-ring-1 c-cursor-pointer"
|
||||
: "hover:c-bg-gray-100 c-cursor-pointer"
|
||||
: ""
|
||||
)}
|
||||
onClick={() => handleClickDay(item, "current")}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "current");
|
||||
onClick={() => {
|
||||
if (style === "google") handleClickDay(item, "current");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">
|
||||
{item}
|
||||
{load_marker(item, "current")}
|
||||
</span>
|
||||
</button>
|
||||
<div className="c-flex c-flex-col c-flex-grow calender-day-wrap">
|
||||
{style === "google" ? (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "current")}
|
||||
className={`${buttonClass(item, "current")}`}
|
||||
// onClick={() => handleClickDay(item, "current")}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "current");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">{item}</span>
|
||||
</button>
|
||||
<div>{load_marker(item, "current")}</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "current")}
|
||||
className={`${buttonClass(item, "current")}`}
|
||||
onClick={() => handleClickDay(item, "current")}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "current");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">
|
||||
{item}
|
||||
{load_marker(item, "current")}
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{calendarData.days.next.map((item, index) => (
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "next")}
|
||||
className={`${buttonClass(item, "next")}`}
|
||||
onClick={() => handleClickDay(item, "next")}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "next");
|
||||
<div
|
||||
className={cx(
|
||||
"calender-grid c-flex c-flex-row",
|
||||
style === "google" ? "hover:c-bg-gray-100 c-cursor-pointer" : ""
|
||||
)}
|
||||
onClick={() => {
|
||||
if (style === "google") handleClickDay(item, "next");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">
|
||||
{item}
|
||||
{load_marker(item, "next")}
|
||||
</span>
|
||||
</button>
|
||||
<div className="c-flex c-flex-col c-flex-grow calender-day-wrap">
|
||||
{style === "google" ? (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "next")}
|
||||
className={`${buttonClass(item, "next")}`}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "next");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">{item}</span>
|
||||
</button>
|
||||
<div>{load_marker(item, "next")}</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
key={index}
|
||||
disabled={isDateDisabled(item, "next")}
|
||||
className={`${buttonClass(item, "next")}`}
|
||||
onClick={() => handleClickDay(item, "next")}
|
||||
onMouseOver={() => {
|
||||
hoverDay(item, "next");
|
||||
}}
|
||||
>
|
||||
<span className="c-relative">
|
||||
{item}
|
||||
{load_marker(item, "next")}
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ import { RoundedButton } from "../utils";
|
|||
interface Props {
|
||||
currentMonth: number;
|
||||
clickMonth: (month: number) => void;
|
||||
style?: string
|
||||
}
|
||||
|
||||
const Months: React.FC<Props> = ({ currentMonth, clickMonth }) => {
|
||||
const Months: React.FC<Props> = ({ currentMonth, clickMonth, style }) => {
|
||||
const { i18n } = useContext(DatepickerContext);
|
||||
loadLanguageModule(i18n);
|
||||
return (
|
||||
|
|
@ -25,7 +26,7 @@ const Months: React.FC<Props> = ({ currentMonth, clickMonth }) => {
|
|||
}}
|
||||
active={currentMonth === item}
|
||||
>
|
||||
<>{dayjs(`2022-${item}-01`).locale(i18n).format("MMM")}</>
|
||||
<>{dayjs(`2022-${item}-01`).locale(i18n).format(style === "google" ? "MMMM" :"MMM")}</>
|
||||
</RoundedButton>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@ import React, { useContext, useMemo } from "react";
|
|||
import { DAYS } from "../../constants";
|
||||
import DatepickerContext from "../../contexts/DatepickerContext";
|
||||
import { loadLanguageModule, shortString, ucFirst } from "../../helpers";
|
||||
|
||||
const Week: React.FC = () => {
|
||||
interface Props {
|
||||
style?: string
|
||||
}
|
||||
const Week: React.FC<Props> = ({style}) => {
|
||||
const { i18n, startWeekOn } = useContext(DatepickerContext);
|
||||
loadLanguageModule(i18n);
|
||||
const startDateModifier = useMemo(() => {
|
||||
console.log(startWeekOn);
|
||||
|
||||
if (startWeekOn) {
|
||||
switch (startWeekOn) {
|
||||
case "mon":
|
||||
|
|
@ -33,19 +37,22 @@ const Week: React.FC = () => {
|
|||
}, [startWeekOn]);
|
||||
|
||||
return (
|
||||
<div className=" c-grid c-grid-cols-7 c-border-b c-border-gray-300 dark:c-border-gray-700 c-py-2">
|
||||
<div className="calender-week c-grid c-grid-cols-7 c-border-b c-border-gray-300 dark:c-border-gray-700 c-py-2">
|
||||
{DAYS.map((item) => (
|
||||
<div
|
||||
key={item}
|
||||
className="c-tracking-wide c-text-gray-500 c-text-center"
|
||||
>
|
||||
{ucFirst(
|
||||
shortString(
|
||||
dayjs(`2022-11-${6 + (item + startDateModifier)}`)
|
||||
{style === "google" ? dayjs(`2022-11-${6 + (item + startDateModifier)}`)
|
||||
.locale(i18n)
|
||||
.format("ddd")
|
||||
)
|
||||
)}
|
||||
.format("dddd") : ucFirst(
|
||||
shortString(
|
||||
dayjs(`2022-11-${6 + (item + startDateModifier)}`)
|
||||
.locale(i18n)
|
||||
.format("dddd")
|
||||
),
|
||||
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ interface Props {
|
|||
changeYear: (year: number) => void;
|
||||
mode?: "monthly" | "daily";
|
||||
onMark?: (day: number, date: Date) => any;
|
||||
style?: string
|
||||
}
|
||||
|
||||
const Calendar: React.FC<Props> = ({
|
||||
|
|
@ -57,6 +58,7 @@ const Calendar: React.FC<Props> = ({
|
|||
changeYear,
|
||||
onMark,
|
||||
mode = "daily",
|
||||
style = "prasi"
|
||||
}) => {
|
||||
// Contexts
|
||||
const {
|
||||
|
|
@ -266,7 +268,7 @@ const Calendar: React.FC<Props> = ({
|
|||
);
|
||||
|
||||
return (
|
||||
<div className="c-w-full md:c-w-[296px] md:c-min-w-[296px]">
|
||||
<div className="c-w-full md:c-w-[296px] md:c-min-w-[296px] calender">
|
||||
<div
|
||||
className={cx(
|
||||
"c-flex c-items-stretch c-space-x-1.5 c-px-2 c-py-1.5",
|
||||
|
|
@ -304,7 +306,7 @@ const Calendar: React.FC<Props> = ({
|
|||
hideYears();
|
||||
}}
|
||||
>
|
||||
<>{calendarData.date.locale(i18n).format("MMM")}</>
|
||||
<>{calendarData.date.locale(i18n).format(style === "google" ? "MMMM" :"MMM")}</>
|
||||
</RoundedButton>
|
||||
</div>
|
||||
|
||||
|
|
@ -341,11 +343,12 @@ const Calendar: React.FC<Props> = ({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={cx("c-mt-0.5 c-min-h-[285px]")}>
|
||||
<div className={cx("c-mt-0.5 c-min-h-[285px] calender-body")}>
|
||||
{showMonths && (
|
||||
<Months
|
||||
currentMonth={calendarData.date.month() + 1}
|
||||
clickMonth={clickMonth}
|
||||
style={style}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
@ -361,13 +364,14 @@ const Calendar: React.FC<Props> = ({
|
|||
|
||||
{!showMonths && !showYears && (
|
||||
<>
|
||||
<Week />
|
||||
<Week style={style}/>
|
||||
|
||||
<Days
|
||||
calendarData={calendarData}
|
||||
onClickPreviousDays={clickPreviousDays}
|
||||
onClickDay={clickDay}
|
||||
onClickNextDays={clickNextDays}
|
||||
style={style}
|
||||
onIcon={(day, date) => {
|
||||
if(typeof onMark === "function"){
|
||||
return onMark(day, date)
|
||||
|
|
|
|||
|
|
@ -174,7 +174,15 @@ export function getNumberOfDay(
|
|||
}
|
||||
}
|
||||
|
||||
[
|
||||
isMobile ? [
|
||||
"S",
|
||||
"M",
|
||||
"T",
|
||||
"W",
|
||||
"T",
|
||||
"F",
|
||||
"S",
|
||||
]: [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
|
|
|
|||
|
|
@ -84,7 +84,8 @@ export interface DatepickerType {
|
|||
popoverDirection?: PopoverDirectionType;
|
||||
mode?: "daily" | "monthly";
|
||||
onMark?: (day: number, date: Date) => any;
|
||||
onLoad?: () => Promise<void>
|
||||
onLoad?: (day: any) => Promise<void>;
|
||||
style?: "google" | "prasi"
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export const QrLabel: FC<{
|
|||
fgcolor: string,
|
||||
size: number
|
||||
}> = ({ value, bgcolor, fgcolor, size }) => {
|
||||
console.log(value);
|
||||
return (
|
||||
<div>
|
||||
<QRCode value={value} size={size}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
import { FC, useEffect, useRef, useState } from "react";
|
||||
import { default as ScanQr } from "qr-scanner";
|
||||
import { QrReaderType } from "./typings";
|
||||
|
||||
export const QrScanner: FC<{ onSuccess: (result: any) => {} }> = ({ onSuccess }) => {
|
||||
const w = window as any;
|
||||
const scanner = useRef<ScanQr>();
|
||||
const videoEl = useRef<HTMLVideoElement>(null);
|
||||
const qrBoxEl = useRef<HTMLDivElement>(null);
|
||||
const [qrOn, setQrOn] = useState<boolean>(true);
|
||||
const [scannedResult, setScannedResult] = useState<string | undefined>("");
|
||||
const [hasScanned, setHasScanned] = useState<boolean>(false);
|
||||
const onScanSuccess = (result: ScanQr.ScanResult) => {
|
||||
if (!hasScanned) {
|
||||
console.log(result);
|
||||
setScannedResult(result?.data);
|
||||
setHasScanned(true);
|
||||
scanner.current?.stop();
|
||||
|
||||
setTimeout(() => {
|
||||
onSuccess(result?.data);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
const onScanFail = (err: string | Error) => {
|
||||
console.log("failed", err);
|
||||
};
|
||||
const openCameraScanner = () => {
|
||||
if (w.AndroidBridge && w.AndroidBridge.openCameraScanner) {
|
||||
w.AndroidBridge.openCameraScanner();
|
||||
} else {
|
||||
console.error("AndroidBridge or openCameraScanner function is not available.");
|
||||
}
|
||||
};
|
||||
if (w.AndroidBridge && w.AndroidBridge.openCameraScanner) {
|
||||
useEffect(() => {
|
||||
openCameraScanner();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
w.onScannerResult = (scannedData: string) => {
|
||||
console.log('Scanned Data:', scannedData);
|
||||
onSuccess(scannedData);
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<div>
|
||||
<h1>QR/Barcode Scanner</h1>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
console.log("Bridge not found");
|
||||
useEffect(() => {
|
||||
if (videoEl?.current && !scanner.current) {
|
||||
scanner.current = new ScanQr(videoEl?.current, onScanSuccess, {
|
||||
onDecodeError: onScanFail,
|
||||
preferredCamera: "environment",
|
||||
highlightScanRegion: true,
|
||||
highlightCodeOutline: true,
|
||||
overlay: qrBoxEl?.current || undefined,
|
||||
});
|
||||
|
||||
scanner?.current
|
||||
?.start()
|
||||
.then(() => setQrOn(true))
|
||||
.catch((err) => {
|
||||
if (err) setQrOn(false);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (!videoEl?.current) {
|
||||
scanner?.current?.stop();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!qrOn)
|
||||
alert(
|
||||
"Kamera tidak bisa diakses. Tolong beri izin untuk akses kamera dan silahkan reload."
|
||||
);
|
||||
}, [qrOn]);
|
||||
|
||||
return (
|
||||
<div className="qr-reader">
|
||||
<video ref={videoEl}></video>
|
||||
<div ref={qrBoxEl} className="qr-box">
|
||||
|
||||
</div>
|
||||
{scannedResult && (
|
||||
<p
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 99999,
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
Scanned Result: {scannedResult}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@ import { Button } from "lib/comps/ui/button";
|
|||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogOverlay,
|
||||
DialogTitle,
|
||||
|
|
@ -73,6 +74,7 @@ export const Pop: FC<{
|
|||
</DialogPrimitive.Close>
|
||||
<DialogHeader className="c-hidden">
|
||||
<DialogTitle></DialogTitle>
|
||||
<DialogDescription></DialogDescription>
|
||||
</DialogHeader>
|
||||
<PassProp
|
||||
pop={{
|
||||
|
|
|
|||
|
|
@ -115,6 +115,13 @@ export const FilterContent: FC<{
|
|||
} catch (ex) {}
|
||||
|
||||
if (mode === "raw" && fm) {
|
||||
if (form && form.fm) {
|
||||
Object.keys(form.fm.data).map((e) => {
|
||||
if (!form?.fm.data?.[e]) {
|
||||
delete form.fm?.data[e];
|
||||
}
|
||||
});
|
||||
}
|
||||
const submit = async (fm: FMLocal) => {
|
||||
fm.render();
|
||||
if (typeof onSubmit === "function") {
|
||||
|
|
|
|||
|
|
@ -43,11 +43,12 @@ export const MasterFilter: FC<FilterProps> = ({
|
|||
if (!isEditor) {
|
||||
const wf = getFilter(name);
|
||||
if (wf) {
|
||||
if (wf.filter.ref[_item.id]) {
|
||||
if (wf.filter.ref?.[_item.id]) {
|
||||
filter.data = wf.filter.ref[_item.id].data;
|
||||
filter.raw_status = "ready";
|
||||
filter.render();
|
||||
} else {
|
||||
filter.data = {};
|
||||
if (mode === "raw" && onLoad) {
|
||||
if (filter.raw_status === "init") {
|
||||
filter.raw_status = "loading";
|
||||
|
|
@ -55,8 +56,24 @@ export const MasterFilter: FC<FilterProps> = ({
|
|||
if (data instanceof Promise) {
|
||||
data.then((e) => {
|
||||
filter.data = e;
|
||||
if (typeof onSubmit === "function") {
|
||||
const data = onSubmit({ data: e } as any);
|
||||
|
||||
if (data instanceof Promise) {
|
||||
data.then((ex) => {
|
||||
filter.data = {
|
||||
__status: "submit",
|
||||
...e,
|
||||
_where: ex,
|
||||
};
|
||||
filter.render();
|
||||
});
|
||||
}
|
||||
console.log({ data });
|
||||
}
|
||||
filter.raw_status = "ready";
|
||||
filter.render();
|
||||
|
||||
});
|
||||
} else {
|
||||
filter.raw_status = "ready";
|
||||
|
|
@ -69,6 +86,9 @@ export const MasterFilter: FC<FilterProps> = ({
|
|||
wf.filter.ref[_item.id] = filter;
|
||||
wf.list.render();
|
||||
}
|
||||
} else {
|
||||
filter.raw_status = "ready";
|
||||
filter.render();
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,411 @@
|
|||
export const generateFilter = (
|
||||
data: any,
|
||||
item: PrasiItem,
|
||||
commit: boolean
|
||||
) => {};
|
||||
export const generateFilter = (data: any, item: PrasiItem, commit: boolean) => {
|
||||
console.log("log", { data, item, commit });
|
||||
};
|
||||
|
||||
const frameFilter = {
|
||||
dim: { h: "full", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "Wrapped",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
bg: { pos: "center", size: "cover", color: "" },
|
||||
dim: { h: "full", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "Wrapped",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "r9u5j1gxxbuv73x8magw7smp",
|
||||
adv: {
|
||||
js: '<ScrollArea className={cx(props.className, "")} orientation={orientation}>{child}</ScrollArea>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'const _jsxFileName = "[item: scroll-area - ehqmu8gsesbvqyxmiw8l580t]";render (React.createElement(ScrollArea, { className: cx(props.className, ""), orientation: orientation, __self: this, __source: {fileName: _jsxFileName, lineNumber: 1}}, child))',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "scroll-area",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
name: "jsx:child",
|
||||
id: "c7nakvqt2ih6zbbrnq59omup",
|
||||
},
|
||||
],
|
||||
script: {
|
||||
props: {
|
||||
orientation: { value: '"vertical"', valueBuilt: '"vertical"' },
|
||||
},
|
||||
},
|
||||
component: {
|
||||
id: "bb74d83b-5fd5-45a5-902d-f2f2ec8a48a7",
|
||||
props: {
|
||||
child: {
|
||||
idx: 1,
|
||||
meta: { type: "content-element" },
|
||||
name: "new_prop_1",
|
||||
type: "string",
|
||||
value: '"hello"',
|
||||
content: {
|
||||
bg: { pos: "center", size: "cover", color: "" },
|
||||
id: "vpvydv6rjhrtw6j9xkgl2t8f",
|
||||
adv: { js: "", css: "", jsBuilt: "render ()" },
|
||||
dim: { h: "full", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "child",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
bg: { pos: "center", size: "cover", color: "" },
|
||||
id: "j1jtff4t8hvk4c2zn2spseww",
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")} id="cek">\n {children}\n</div>',
|
||||
jsBuilt:
|
||||
'const _jsxFileName = "[item: absolute - bs6mzs6otarkqrqciv6hd0to]";render (React.createElement(\'div\', { ...props, className: cx(props.className, ""), id: "cek", __self: this, __source: {fileName: _jsxFileName, lineNumber: 1}}\n , children\n))',
|
||||
},
|
||||
dim: { h: "full", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "absolute",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "tlfpdpv1g6y7f7klumtbecet",
|
||||
dim: {
|
||||
h: "fit",
|
||||
w: "full",
|
||||
hUnit: "px",
|
||||
wUnit: "px",
|
||||
},
|
||||
name: "container",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "epmv1gh58uso1iyi747oqlpf",
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "form-fields")}>\n {children}\n</div>',
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "form-fields") }, children));\n',
|
||||
},
|
||||
dim: {
|
||||
h: "full",
|
||||
w: "full",
|
||||
hUnit: "px",
|
||||
wUnit: "px",
|
||||
},
|
||||
name: "fields-filter",
|
||||
type: "item",
|
||||
childs: [],
|
||||
layout: {
|
||||
dir: "row",
|
||||
gap: 0,
|
||||
wrap: "flex-wrap",
|
||||
align: "top-left",
|
||||
},
|
||||
script: {},
|
||||
},
|
||||
],
|
||||
hidden: false,
|
||||
},
|
||||
],
|
||||
hidden: false,
|
||||
script: {},
|
||||
padding: { b: 0, l: 0, r: 5, t: 0 },
|
||||
},
|
||||
],
|
||||
script: {},
|
||||
},
|
||||
valueBuilt: '"hello"',
|
||||
jsxCalledBy: [
|
||||
"yych4cm4do7t4jt0d42dasrk",
|
||||
"ehqmu8gsesbvqyxmiw8l580t",
|
||||
],
|
||||
},
|
||||
orientation: {
|
||||
idx: 1,
|
||||
meta: {
|
||||
type: "option",
|
||||
options: '["horizontal", "vertical"]',
|
||||
optionsBuilt: '["horizontal", "vertical"]',
|
||||
},
|
||||
name: "new_prop_1",
|
||||
type: "string",
|
||||
value: '"vertical"',
|
||||
valueBuilt: '"vertical"',
|
||||
},
|
||||
},
|
||||
ref_ids: {},
|
||||
useStyle: true,
|
||||
},
|
||||
hidden: false,
|
||||
},
|
||||
],
|
||||
hidden: false,
|
||||
},
|
||||
{
|
||||
id: "s9kb580m1bjmpe4xj9dtkgnz",
|
||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "Wrapped",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "hf0pxf4slu2xqhcuoropnkc6",
|
||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "Reset",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "jvnbd14f1sgcnmdhy4dcfuo4",
|
||||
adv: {
|
||||
js: '<Button\n {...props}\n onClick={(e) => {\n if (!isEditor) on_click(e);\n }}\n variant={variant !== "primary" ? variant : undefined}\n size={size !== "default" ? size : undefined}\n>\n {label}\n</Button>',
|
||||
css: "& {\n display: flex;\n\n &:hover {\n cursor: pointer;\n\n\n\n\n\n // &.mobile {}\n // &.desktop {}\n // &:hover {}\n }\n}",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement(\n Button,\n {\n ...props,\n onClick: (e) => {\n if (!isEditor)\n on_click(e);\n },\n variant: variant !== "primary" ? variant : void 0,\n size: size !== "default" ? size : void 0\n },\n label\n));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "button",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
name: "jsx: label",
|
||||
id: "k59ppuxhzf4tnkb4b4enyxxe",
|
||||
},
|
||||
],
|
||||
mobile: { linktag: {} },
|
||||
script: {
|
||||
props: {
|
||||
size: { value: ' "default";\n', valueBuilt: ' "default";\n' },
|
||||
variant: { value: '"ghost"', valueBuilt: '"ghost"' },
|
||||
on_click: {
|
||||
value:
|
||||
'async (e) => {\r\n fm.data = {};\r\n filter.data = {};\r\n filter.render();\r\n fm.render();\r\n await fm.submit();\r\n sheet.close();\r\n // const res = getFilter("root");\r\n // res.list.reload();\r\n}',
|
||||
valueBuilt:
|
||||
'async (e) => {\r\n fm.data = {};\r\n filter.data = {};\r\n filter.render();\r\n fm.render();\r\n await fm.submit();\r\n sheet.close();\r\n // const res = getFilter("root");\r\n // res.list.reload();\r\n}',
|
||||
},
|
||||
},
|
||||
},
|
||||
component: {
|
||||
id: "a15d152d-0118-408f-89f1-f6b2dfbd2e05",
|
||||
props: {
|
||||
size: {
|
||||
idx: 5,
|
||||
meta: {
|
||||
type: "option",
|
||||
options:
|
||||
'["default", "xs", "sm", "lg", "icon", "nosize"]',
|
||||
optionsBuilt:
|
||||
' ["default", "xs", "sm", "lg", "icon", "nosize"];\n',
|
||||
},
|
||||
name: "prop_5",
|
||||
type: "string",
|
||||
value: '"default"',
|
||||
valueBuilt: ' "default";\n',
|
||||
},
|
||||
label: {
|
||||
idx: 1,
|
||||
meta: { type: "content-element" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value: '"hello"',
|
||||
content: {
|
||||
id: "bb91ryll6mtk827zpibo6k65",
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n {children}\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, children));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "label",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "zhmnkaup9uxpou42lyn4splr",
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n Reset\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'const _jsxFileName = "[item: new_text - feo7cgson0fo2zjjujwqkr8l]";render (React.createElement(\'div\', { ...props, className: cx(props.className, ""), __self: this, __source: {fileName: _jsxFileName, lineNumber: 1}}, "Reset"\n\n))',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
html: "submit",
|
||||
name: "new_text",
|
||||
text: "",
|
||||
type: "text",
|
||||
layout: { dir: "col", gap: 0, align: "center" },
|
||||
script: {},
|
||||
},
|
||||
],
|
||||
script: {},
|
||||
},
|
||||
valueBuilt: '"hello"',
|
||||
jsxCalledBy: [
|
||||
"frq12uxc65i9zn8myzan4huk",
|
||||
"q278u9p4cejubvfwqc72ey73",
|
||||
],
|
||||
},
|
||||
variant: {
|
||||
idx: 3,
|
||||
meta: {
|
||||
type: "option",
|
||||
options:
|
||||
'["primary", "secondary", "outline", "ghost", "link", "destructive","no-style"]',
|
||||
option_mode: "button",
|
||||
optionsBuilt:
|
||||
' ["primary", "secondary", "outline", "ghost", "link", "destructive", "no-style"];\n',
|
||||
},
|
||||
name: "prop_3",
|
||||
type: "string",
|
||||
value: '"ghost"',
|
||||
valueBuilt: '"ghost"',
|
||||
},
|
||||
on_click: {
|
||||
idx: 1,
|
||||
meta: { type: "text" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value:
|
||||
'async (e: React.MouseEvent<HTMLDivElement>) => {\r\n fm.data = {};\r\n filter.data = {};\r\n filter.render();\r\n fm.render();\r\n await fm.submit();\r\n sheet.close();\r\n // const res = getFilter("root");\r\n // res.list.reload();\r\n}',
|
||||
valueBuilt:
|
||||
'async (e) => {\r\n fm.data = {};\r\n filter.data = {};\r\n filter.render();\r\n fm.render();\r\n await fm.submit();\r\n sheet.close();\r\n // const res = getFilter("root");\r\n // res.list.reload();\r\n}',
|
||||
},
|
||||
},
|
||||
},
|
||||
originalId: "q278u9p4cejubvfwqc72ey73",
|
||||
},
|
||||
],
|
||||
padding: { b: 10, l: 10, r: 0, t: 10 },
|
||||
},
|
||||
{
|
||||
id: "zidglf2tal6pgxe6c1ey7i5x",
|
||||
dim: { h: "fit", w: "full", hUnit: "px", wUnit: "px" },
|
||||
name: "Apply",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "hjaeik76bqh3ufszscmzw0bm",
|
||||
adv: {
|
||||
js: '<Button\n {...props}\n onClick={(e) => {\n if (!isEditor) on_click(e);\n }}\n variant={variant !== "primary" ? variant : undefined}\n size={size !== "default" ? size : undefined}\n>\n {label}\n</Button>',
|
||||
css: "& {\n display: flex;\n\n &:hover {\n cursor: pointer;\n\n\n\n\n\n // &.mobile {}\n // &.desktop {}\n // &:hover {}\n }\n}",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement(\n Button,\n {\n ...props,\n onClick: (e) => {\n if (!isEditor)\n on_click(e);\n },\n variant: variant !== "primary" ? variant : void 0,\n size: size !== "default" ? size : void 0\n },\n label\n));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "button",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
name: "jsx: label",
|
||||
id: "w8i2j4uq3a186ozueanxisx9",
|
||||
originalId: "hglwmigw09h2b8a9vlz2cme5",
|
||||
},
|
||||
],
|
||||
mobile: { linktag: {} },
|
||||
script: {
|
||||
props: {
|
||||
size: { value: ' "default";\n', valueBuilt: ' "default";\n' },
|
||||
variant: {
|
||||
value: ' "primary";\n',
|
||||
valueBuilt: ' "primary";\n',
|
||||
},
|
||||
on_click: {
|
||||
value:
|
||||
'async (e) => {\r\n await fm.submit();\r\n const res = getFilter("root");\r\n res.list.reload();\r\n sheet.close();\r\n}',
|
||||
valueBuilt:
|
||||
'async (e) => {\r\n await fm.submit();\r\n const res = getFilter("root");\r\n res.list.reload();\r\n sheet.close();\r\n}',
|
||||
},
|
||||
},
|
||||
},
|
||||
component: {
|
||||
id: "a15d152d-0118-408f-89f1-f6b2dfbd2e05",
|
||||
props: {
|
||||
size: {
|
||||
idx: 5,
|
||||
meta: {
|
||||
type: "option",
|
||||
options:
|
||||
'["default", "xs", "sm", "lg", "icon", "nosize"]',
|
||||
optionsBuilt:
|
||||
' ["default", "xs", "sm", "lg", "icon", "nosize"];\n',
|
||||
},
|
||||
name: "prop_5",
|
||||
type: "string",
|
||||
value: '"default"',
|
||||
valueBuilt: ' "default";\n',
|
||||
},
|
||||
label: {
|
||||
idx: 1,
|
||||
meta: { type: "content-element" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value: '"hello"',
|
||||
content: {
|
||||
id: "dlq5kemqyq8d0os6uu34l4wd",
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n {children}\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'render(/* @__PURE__ */ React.createElement("div", { ...props, className: cx(props.className, "") }, children));\n',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
name: "label",
|
||||
type: "item",
|
||||
childs: [
|
||||
{
|
||||
id: "nbho83c6uggcc4mxjn0e2tr9",
|
||||
adv: {
|
||||
js: '<div {...props} className={cx(props.className, "")}>\n Apply\n</div>',
|
||||
css: "",
|
||||
jsBuilt:
|
||||
'const _jsxFileName = "[item: new_text - to0gkiai6fbns9utxj6re1pw]";render (React.createElement(\'div\', { ...props, className: cx(props.className, ""), __self: this, __source: {fileName: _jsxFileName, lineNumber: 1}}, "Apply"\n\n))',
|
||||
},
|
||||
dim: { h: "full", w: "full" },
|
||||
html: "submit",
|
||||
name: "new_text",
|
||||
text: "",
|
||||
type: "text",
|
||||
layout: { dir: "col", gap: 0, align: "center" },
|
||||
script: {},
|
||||
},
|
||||
],
|
||||
script: {},
|
||||
},
|
||||
valueBuilt: '"hello"',
|
||||
jsxCalledBy: [
|
||||
"frq12uxc65i9zn8myzan4huk",
|
||||
"q278u9p4cejubvfwqc72ey73",
|
||||
],
|
||||
},
|
||||
variant: {
|
||||
idx: 3,
|
||||
meta: {
|
||||
type: "option",
|
||||
options:
|
||||
'["primary", "secondary", "outline", "ghost", "link", "destructive","no-style"]',
|
||||
option_mode: "button",
|
||||
optionsBuilt:
|
||||
' ["primary", "secondary", "outline", "ghost", "link", "destructive", "no-style"];\n',
|
||||
},
|
||||
name: "prop_3",
|
||||
type: "string",
|
||||
value: '"primary"',
|
||||
valueBuilt: ' "primary";\n',
|
||||
},
|
||||
on_click: {
|
||||
idx: 1,
|
||||
meta: { type: "text" },
|
||||
name: "prop_1",
|
||||
type: "string",
|
||||
value:
|
||||
'async (e: React.MouseEvent<HTMLDivElement>) => {\r\n await fm.submit();\r\n const res = getFilter("root");\r\n res.list.reload();\r\n sheet.close();\r\n}',
|
||||
valueBuilt:
|
||||
'async (e) => {\r\n await fm.submit();\r\n const res = getFilter("root");\r\n res.list.reload();\r\n sheet.close();\r\n}',
|
||||
},
|
||||
},
|
||||
},
|
||||
originalId: "q278u9p4cejubvfwqc72ey73",
|
||||
},
|
||||
],
|
||||
padding: { b: 10, l: 10, r: 0, t: 10 },
|
||||
},
|
||||
],
|
||||
layout: { dir: "row", gap: 0, wrap: "flex-nowrap", align: "top-left" },
|
||||
padding: { b: 0, l: 5, r: 5, t: 0 },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export const BaseField = (prop: {
|
|||
"filled"
|
||||
)}
|
||||
>
|
||||
{arg.show_label !== "n" && <Label field={field} fm={fm} />}
|
||||
{arg.show_label !== "n" && <Label field={field} fm={fm} arg={arg}/>}
|
||||
<div className="field-input c-flex c-flex-1 c-flex-col">
|
||||
<div
|
||||
className={cx(
|
||||
|
|
|
|||
|
|
@ -104,7 +104,15 @@ export const Field: FC<FieldProp> = (arg) => {
|
|||
|
||||
const disabled =
|
||||
typeof field.disabled === "function" ? field.disabled() : field.disabled;
|
||||
if (field.hidden) return <></>;
|
||||
const show =
|
||||
typeof field.hidden === "function"
|
||||
? field.hidden()
|
||||
: typeof field.hidden === "string"
|
||||
? field.hidden === "n"
|
||||
? false
|
||||
: true
|
||||
: typeof field.hidden === "boolean"? field.hidden : true;
|
||||
if (!show) return <></>;
|
||||
|
||||
return (
|
||||
<LabelDiv
|
||||
|
|
@ -145,7 +153,7 @@ export const Field: FC<FieldProp> = (arg) => {
|
|||
)}
|
||||
ref={typeof arg.field_ref === "function" ? arg.field_ref : undefined}
|
||||
>
|
||||
{showlabel !== "n" && field.label && <Label field={field} fm={fm} />}
|
||||
{showlabel !== "n" && field.label && <Label field={field} fm={fm} arg={arg}/>}
|
||||
<div className={cx("field-input c-flex c-flex-1 c-flex-col")}>
|
||||
<FieldInput
|
||||
field={field}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { FieldTypeInput, PropTypeInput } from "./type/TypeInput";
|
|||
import { FieldLink } from "./type/TypeLink";
|
||||
import { MultiOption } from "./type/TypeMultiOption";
|
||||
import { SingleOption } from "./type/TypeSingleOption";
|
||||
import { TableListEdit } from "app/comps/table-list-edit/TableListEdit";
|
||||
|
||||
export const FieldInput: FC<{
|
||||
field: FieldLocal;
|
||||
|
|
@ -58,6 +59,7 @@ export const FieldInput: FC<{
|
|||
child: get(_item, "edit.props.child.value") as PrasiItem,
|
||||
bottom: childsTableEdit.find((e) => e.name === "bottom") as PrasiItem,
|
||||
};
|
||||
console.log({ tableEdit });
|
||||
table_edit = (
|
||||
<TableEdit
|
||||
on_init={() => {
|
||||
|
|
@ -74,6 +76,35 @@ export const FieldInput: FC<{
|
|||
);
|
||||
}
|
||||
|
||||
let table_list_edit = null;
|
||||
if (type_field === "multi-option" && arg.sub_type === "table-list-edit") {
|
||||
const childsTableEdit = get(
|
||||
_item,
|
||||
"edit.props.child.value.childs"
|
||||
) as unknown as Array<PrasiItem>;
|
||||
const tableListEdit = {
|
||||
child: get(_item, "edit.props.child.value") as PrasiItem,
|
||||
bottom: childsTableEdit.find((e) => e.name === "bottom") as PrasiItem,
|
||||
};
|
||||
table_list_edit = (
|
||||
<TableListEdit
|
||||
on_init={() => {
|
||||
return fm;
|
||||
}}
|
||||
field = {field}
|
||||
arg={arg}
|
||||
show_header={arg.tbl_show_header}
|
||||
name={arg.name}
|
||||
child={child}
|
||||
PassProp={PassProp}
|
||||
item={_item}
|
||||
bottom={tableListEdit.bottom}
|
||||
body={tableListEdit.child}
|
||||
fm={fm}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let not_ready: any = false;
|
||||
if (
|
||||
arg.type === "multi-option" &&
|
||||
|
|
@ -184,6 +215,8 @@ export const FieldInput: FC<{
|
|||
) : ["multi-option"].includes(type_field) ? (
|
||||
arg.sub_type === "table-edit" ? (
|
||||
table_edit
|
||||
) : arg.sub_type === "table-list-edit" ? (
|
||||
table_list_edit
|
||||
) : (
|
||||
<MultiOption arg={arg} field={field} fm={fm} />
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,36 +1,62 @@
|
|||
import { FC } from "react";
|
||||
import { FMLocal, FieldLocal } from "../typings";
|
||||
import { FC, useEffect } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../typings";
|
||||
|
||||
export const Label: FC<{ field: FieldLocal; fm: FMLocal }> = ({
|
||||
export const Label: FC<{ field: FieldLocal; fm: FMLocal; arg: FieldProp }> = ({
|
||||
field,
|
||||
fm,
|
||||
arg,
|
||||
}) => {
|
||||
const errors = fm.error.get(field.name);
|
||||
const disabled =
|
||||
typeof field.disabled === "function" ? field.disabled() : field.disabled;
|
||||
useEffect(() => {
|
||||
if (field.name === "complete_description")
|
||||
console.log("log", field.required);
|
||||
}, []);
|
||||
const required =
|
||||
typeof arg.required === "string"
|
||||
? arg.required === "y"
|
||||
: typeof arg.required === "function"
|
||||
? arg.required()
|
||||
: false;
|
||||
if (typeof required === "boolean" && field.required !== required) {
|
||||
field.required = required;
|
||||
field.render();
|
||||
}
|
||||
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 && !disabled && (
|
||||
<span className="c-text-red-600 c-mb-2 c-ml-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M12 6v12" />
|
||||
<path d="M17.196 9 6.804 15" />
|
||||
<path d="m6.804 9 10.392 6" />
|
||||
</svg>
|
||||
<div
|
||||
className={cx(
|
||||
"label c-text-sm c-flex c-items-center",
|
||||
"c-mt-3 c-w-full c-justify-between"
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<span className={cx(errors.length > 0 && `c-text-red-600`)}>
|
||||
{field.label}
|
||||
</span>
|
||||
{required && !disabled && (
|
||||
<span className="c-text-red-600 c-mb-2 c-ml-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="M12 6v12" />
|
||||
<path d="M17.196 9 6.804 15" />
|
||||
<path d="m6.804 9 10.392 6" />
|
||||
</svg>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{field.label_action && (
|
||||
<div className="c-self-end">{field.label_action}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -71,96 +71,106 @@ export const TableEdit: FC<{
|
|||
const label = getProp(child, "title", "");
|
||||
const type = getProp(child, "type", "");
|
||||
const width = parseInt(getProp(child, "width", {}));
|
||||
if (type === "checkbox") {
|
||||
const on_click = getProp(child, "opt__on_click", "");
|
||||
columns.push({
|
||||
key,
|
||||
name,
|
||||
width: 35,
|
||||
minWidth: 45,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
frozen: true,
|
||||
renderCell(arg: any) {
|
||||
const { props, tbl } = arg;
|
||||
local.tbl = tbl;
|
||||
const key = props.column.key;
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: key,
|
||||
value: props.row[props.column.key],
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={tbl.data}
|
||||
fm={props.fm}
|
||||
fm_parent={parent}
|
||||
ext_fm={{
|
||||
idx: props.rowIdx,
|
||||
change: () => {},
|
||||
remove: () => {
|
||||
const data =
|
||||
tbl.data.filter((e: any) => e !== props.row) || [];
|
||||
fm.data[name] = data;
|
||||
fm.render();
|
||||
},
|
||||
add: (e: any) => {
|
||||
tbl.data.push(e ? e : {});
|
||||
fm.render();
|
||||
},
|
||||
}}
|
||||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
columns.push({
|
||||
key,
|
||||
label,
|
||||
width: width > 0 ? width : undefined,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
renderCell(arg: any) {
|
||||
const { props, tbl } = arg;
|
||||
local.tbl = tbl;
|
||||
const key = props.column.key;
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: key,
|
||||
value: props.row[props.column.key],
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={tbl.data}
|
||||
fm={props.fm}
|
||||
fm_parent={parent}
|
||||
ext_fm={{
|
||||
idx: props.rowIdx,
|
||||
change: () => {},
|
||||
remove: () => {
|
||||
const data =
|
||||
tbl.data.filter((e: any) => e !== props.row) || [];
|
||||
fm.data[name] = data;
|
||||
fm.render();
|
||||
},
|
||||
add: (e: any) => {
|
||||
tbl.data.push(e ? e : {});
|
||||
fm.render();
|
||||
},
|
||||
}}
|
||||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
const show = getProp(child, "show", {});
|
||||
let is_show =
|
||||
typeof show === "function"
|
||||
? show({ data: fm.data })
|
||||
: typeof show === "string"
|
||||
? show === "n"
|
||||
? false
|
||||
: true
|
||||
: true;
|
||||
if (is_show)
|
||||
if (type === "checkbox") {
|
||||
const on_click = getProp(child, "opt__on_click", "");
|
||||
columns.push({
|
||||
key,
|
||||
name,
|
||||
width: 35,
|
||||
minWidth: 45,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
frozen: true,
|
||||
renderCell(arg: any) {
|
||||
const { props, tbl } = arg;
|
||||
local.tbl = tbl;
|
||||
const key = props.column.key;
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: key,
|
||||
value: props.row[props.column.key],
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={tbl.data}
|
||||
fm={props.fm}
|
||||
fm_parent={parent}
|
||||
ext_fm={{
|
||||
idx: props.rowIdx,
|
||||
change: () => {},
|
||||
remove: () => {
|
||||
const data =
|
||||
tbl.data.filter((e: any) => e !== props.row) || [];
|
||||
fm.data[name] = data;
|
||||
fm.render();
|
||||
},
|
||||
add: (e: any) => {
|
||||
tbl.data.push(e ? e : {});
|
||||
fm.render();
|
||||
},
|
||||
}}
|
||||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
columns.push({
|
||||
key,
|
||||
label,
|
||||
width: width > 0 ? width : undefined,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
renderCell(arg: any) {
|
||||
const { props, tbl } = arg;
|
||||
local.tbl = tbl;
|
||||
const key = props.column.key;
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: key,
|
||||
value: props.row[props.column.key],
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={tbl.data}
|
||||
fm={props.fm}
|
||||
fm_parent={parent}
|
||||
ext_fm={{
|
||||
idx: props.rowIdx,
|
||||
change: () => {},
|
||||
remove: () => {
|
||||
const data =
|
||||
tbl.data.filter((e: any) => e !== props.row) || [];
|
||||
fm.data[name] = data;
|
||||
fm.render();
|
||||
},
|
||||
add: (e: any) => {
|
||||
tbl.data.push(e ? e : {});
|
||||
fm.render();
|
||||
},
|
||||
}}
|
||||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
|
|
@ -190,6 +200,7 @@ export const TableEdit: FC<{
|
|||
`
|
||||
)}
|
||||
>
|
||||
{/* {JSON.stringify(value.map((e) => e.id))} */}
|
||||
<table
|
||||
className={cx(
|
||||
"c-table-auto",
|
||||
|
|
@ -255,15 +266,7 @@ export const TableEdit: FC<{
|
|||
<>
|
||||
{value.map((row: any, idx: number) => {
|
||||
return (
|
||||
<BaseForm
|
||||
is_form={false}
|
||||
data={row}
|
||||
on_change={(_fm) => {
|
||||
fm.data[name][idx] = _fm.data;
|
||||
fm.data[name] = [...fm.data[name]];
|
||||
fm.render();
|
||||
}}
|
||||
>
|
||||
<BaseForm is_form={false} data={row}>
|
||||
{(form) => {
|
||||
return (
|
||||
<tr>
|
||||
|
|
@ -289,7 +292,10 @@ export const TableEdit: FC<{
|
|||
row: row,
|
||||
rowIdx: idx,
|
||||
column: header,
|
||||
fm: form.fm,
|
||||
fm: {
|
||||
...form.fm,
|
||||
data: row,
|
||||
},
|
||||
},
|
||||
tbl: {
|
||||
data: value,
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ export const FieldButton: FC<{
|
|||
if (arg.type === "multi-option") {
|
||||
return (
|
||||
<>
|
||||
<div className={cx("c-flex c-items-center c-w-full c-flex-row")}>
|
||||
<div className={cx("c-flex c-items-center c-w-full c-flex-row c-max-w-full")}>
|
||||
<div
|
||||
className={cx(
|
||||
`c-flex`,
|
||||
`c-flex c-flex-wrap`,
|
||||
css`
|
||||
gap: 0.5rem;
|
||||
`
|
||||
|
|
@ -58,10 +58,11 @@ export const FieldButton: FC<{
|
|||
} else {
|
||||
selected.push(item);
|
||||
}
|
||||
if(selected.length) selected = selected.filter((e) => e)
|
||||
arg.opt_set_value({
|
||||
fm,
|
||||
name: field.name,
|
||||
selected: selected.map((e) => e.value),
|
||||
selected: selected.length ? selected.map((e) => e.value) : [],
|
||||
options: local.list,
|
||||
type: field.type,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export const TypeDropdown: FC<{
|
|||
fm: FMLocal;
|
||||
arg: FieldProp;
|
||||
}> = ({ field, fm, arg }) => {
|
||||
|
||||
const local = useLocal({
|
||||
loaded: false,
|
||||
options: [] as { value: string; label: string; data: any }[],
|
||||
|
|
@ -164,7 +165,14 @@ export const TypeDropdown: FC<{
|
|||
}
|
||||
const disabled =
|
||||
typeof field.disabled === "function" ? field.disabled() : field.disabled;
|
||||
|
||||
const disabled_search =
|
||||
typeof field.disabled_search === "function"
|
||||
? field.disabled_search()
|
||||
: typeof field.disabled_search === "string"
|
||||
? field.disabled_search === "n"
|
||||
? true
|
||||
: false
|
||||
: field.disabled_search;
|
||||
if (!local.loaded) return <FieldLoading />;
|
||||
|
||||
if (field.type === "single-option") {
|
||||
|
|
@ -179,6 +187,7 @@ export const TypeDropdown: FC<{
|
|||
<>
|
||||
<Typeahead
|
||||
value={typeahead_val}
|
||||
disabledSearch={disabled_search ? true : false}
|
||||
popupClassName={popupClassName}
|
||||
onSelect={({ search, item }) => {
|
||||
if (item) {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ export const FieldTypeInput: FC<{
|
|||
case "toggle":
|
||||
return (
|
||||
<div className="c-px-2">
|
||||
ad
|
||||
<div
|
||||
className={cx(
|
||||
"c-relative",
|
||||
|
|
@ -222,6 +221,10 @@ export const FieldTypeInput: FC<{
|
|||
? new Date(value?.startDate)
|
||||
: null;
|
||||
renderOnChange();
|
||||
|
||||
if (prop.onChange) {
|
||||
prop.onChange(fm.data[field.name]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,11 @@ export const FieldLink: FC<{
|
|||
if (!(await navigateLink(arg.link, field, fm.deps.md))) {
|
||||
link_local.navigating = false;
|
||||
link_local.render();
|
||||
setTimeout(() => {
|
||||
|
||||
local.init = true;
|
||||
local.render();
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
|
@ -168,10 +173,11 @@ export type LinkParam = {
|
|||
}[];
|
||||
};
|
||||
|
||||
const navigateLink = async (
|
||||
export const navigateLink = async (
|
||||
link: FieldProp["link"],
|
||||
field: FieldLocal,
|
||||
md?: MDLocal
|
||||
md?: MDLocal,
|
||||
prm? :any
|
||||
) => {
|
||||
let params = link.params(field) as { where: any; create: any; update: any };
|
||||
|
||||
|
|
@ -217,20 +223,26 @@ const navigateLink = async (
|
|||
values.hash = vhash;
|
||||
|
||||
link_cache[vhash] = values;
|
||||
|
||||
if (!link.url) {
|
||||
alert("No URL defined!");
|
||||
if (typeof link.url === "function") {
|
||||
if (md) {
|
||||
link.url(md.selected[md.pk?.name || ""]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!link.url) {
|
||||
alert("No URL defined!");
|
||||
return false;
|
||||
}
|
||||
|
||||
await api._kv("set", vhash, values);
|
||||
const lnk = location.hash.split("#").find((e) => e.startsWith("lnk="));
|
||||
let prev_link = "";
|
||||
if (lnk) {
|
||||
prev_link = lnk.split("=").pop() || "";
|
||||
if (prev_link) prev_link = prev_link + "+";
|
||||
}
|
||||
await api._kv("set", vhash, values);
|
||||
const lnk = location.hash.split("#").find((e) => e.startsWith("lnk="));
|
||||
let prev_link = "";
|
||||
if (lnk) {
|
||||
prev_link = lnk.split("=").pop() || "";
|
||||
if (prev_link) prev_link = prev_link + "+";
|
||||
}
|
||||
|
||||
navigate(`${link.url}#lnk=${prev_link + vhash}`);
|
||||
return true;
|
||||
navigate(`${link.url}#lnk=${prev_link + vhash}${prm}`);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export const FieldMoney: FC<{
|
|||
input.render();
|
||||
}
|
||||
}}
|
||||
value={formatCurrency(input.value)}
|
||||
value={formatCurrency(input.value) || 0}
|
||||
disabled={disabled}
|
||||
className={cx(
|
||||
"c-flex-1 c-bg-transparent c-outline-none c-px-2 c-text-sm c-w-full"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export const generateField = async (
|
|||
pk: generateSelect(parseGenField(master.value.checked)).pk,
|
||||
table: master?.name,
|
||||
select: generateSelect(parseGenField(master.value.checked)).select,
|
||||
pks: {},
|
||||
pks: {},
|
||||
type: fieldType,
|
||||
} as any);
|
||||
const result = {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ type FieldType =
|
|||
export type FieldProp = {
|
||||
name: string;
|
||||
label: string;
|
||||
label_action: ReactNode;
|
||||
desc?: string;
|
||||
props?: any;
|
||||
mask?: string;
|
||||
|
|
@ -63,7 +64,7 @@ export type FieldProp = {
|
|||
field: FieldLocal;
|
||||
Link: FC<{ children: any }>;
|
||||
}) => Promise<string> | string);
|
||||
url: string;
|
||||
url: string | ((e?: any) => void);
|
||||
params: (field: FieldLocal) => { where: any } | Promise<{ where: any }>;
|
||||
};
|
||||
fm: FMLocal;
|
||||
|
|
@ -127,6 +128,8 @@ export type FieldProp = {
|
|||
max_date?: any;
|
||||
min_date?: any;
|
||||
upload_style?: "inline" | "full";
|
||||
disabled_search?: (() => Promise<boolean> | boolean) | boolean | "y" | "n";
|
||||
show?: (() => boolean) | boolean | "y" | "n";
|
||||
};
|
||||
|
||||
export type FMInternal = {
|
||||
|
|
@ -170,13 +173,14 @@ export type FieldInternal<T extends FieldProp["type"]> = {
|
|||
name: FieldProp["name"];
|
||||
type: T | (() => T);
|
||||
label: FieldProp["label"];
|
||||
label_action: FieldProp["label_action"];
|
||||
desc: FieldProp["desc"];
|
||||
prefix: FieldProp["prefix"];
|
||||
suffix: FieldProp["suffix"];
|
||||
width: FieldProp["width"];
|
||||
required: boolean;
|
||||
focused: boolean;
|
||||
hidden: boolean;
|
||||
hidden: (() => boolean) | boolean | "y" | "n";
|
||||
disabled: boolean | (() => boolean);
|
||||
required_msg: FieldProp["required_msg"];
|
||||
col?: GFCol;
|
||||
|
|
@ -200,6 +204,7 @@ export type FieldInternal<T extends FieldProp["type"]> = {
|
|||
min_date?: FieldProp["min_date"];
|
||||
error?: any;
|
||||
table_fields?: any[];
|
||||
disabled_search?: (() => Promise<boolean> | boolean) | boolean | "y" | "n";
|
||||
};
|
||||
export type FieldLocal = FieldInternal<any> & {
|
||||
render: () => void;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
const toastSuccess = (opt: { addNewText: string }) => {
|
||||
const md = fm.deps.md as MDLocal;
|
||||
fm.save_status = "saved";
|
||||
|
||||
if (md) {
|
||||
toast.success(
|
||||
<div
|
||||
|
|
@ -110,7 +109,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
</div>
|
||||
</div>,
|
||||
{
|
||||
duration: 60 * 1000,
|
||||
duration:3000,
|
||||
className: css`
|
||||
background: #e4ffed;
|
||||
border: 2px solid green;
|
||||
|
|
@ -135,7 +134,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
</div>
|
||||
</div>,
|
||||
{
|
||||
duration: 60 * 1000,
|
||||
duration:3000,
|
||||
className: css`
|
||||
background: #e4ffed;
|
||||
border: 2px solid green;
|
||||
|
|
@ -233,7 +232,6 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const form = JSON.parse(JSON.stringify(fm.data));
|
||||
|
||||
if (fm.deps.md) {
|
||||
|
|
@ -291,6 +289,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
|||
}
|
||||
);
|
||||
} else {
|
||||
|
||||
toastSuccess({ addNewText: lang.t("Add New") });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,18 +21,20 @@ export const useField = (
|
|||
|
||||
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();
|
||||
typeof arg.required === "string" ? arg.required === "y" : arg.required();
|
||||
const update_field = {
|
||||
name: name.replace(/\s*/gi, ""),
|
||||
label: label,
|
||||
label_action: arg.label_action,
|
||||
type: arg.type,
|
||||
desc: arg.desc,
|
||||
prefix: arg.prefix,
|
||||
suffix: arg.suffix,
|
||||
width: arg.width,
|
||||
custom: arg.custom,
|
||||
required: required === "y",
|
||||
required: typeof required === "string" ? required === "y" : required,
|
||||
required_msg: arg.required_msg,
|
||||
disabled:
|
||||
typeof arg.disabled === "function" ? arg.disabled : arg.disabled === "y",
|
||||
|
|
@ -40,7 +42,10 @@ export const useField = (
|
|||
max_date: arg.max_date,
|
||||
min_date: arg.min_date,
|
||||
table_fields: [],
|
||||
disabled_search: arg.disabled_search,
|
||||
hidden: arg.show
|
||||
};
|
||||
|
||||
|
||||
if (field.status === "init" || isEditor) {
|
||||
for (const [k, v] of Object.entries(update_field)) {
|
||||
|
|
@ -49,7 +54,6 @@ export const useField = (
|
|||
}
|
||||
|
||||
const fm = arg.fm;
|
||||
|
||||
useEffect(() => {
|
||||
if (field.status === "init" || !fm.fields[name]) {
|
||||
field.status = "ready";
|
||||
|
|
@ -60,7 +64,10 @@ export const useField = (
|
|||
field.render();
|
||||
}
|
||||
}, []);
|
||||
|
||||
field.prop = arg as any;
|
||||
|
||||
if(field.name === "complete_description") console.log(update_field);
|
||||
if(field.name === "complete_description") console.log(field);
|
||||
return field;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ export const Import: FC<{
|
|||
task,
|
||||
}: {
|
||||
list: any[];
|
||||
task: (e: any) => Promise<void>;
|
||||
task: (e: any, index: number) => Promise<void>;
|
||||
}) => {
|
||||
let n = 0;
|
||||
while (n < list.length) {
|
||||
|
|
@ -99,7 +99,7 @@ export const Import: FC<{
|
|||
});
|
||||
}
|
||||
|
||||
await task(list[n]);
|
||||
await task(list[n], n);
|
||||
await sleep(100);
|
||||
n++;
|
||||
}
|
||||
|
|
@ -108,9 +108,9 @@ export const Import: FC<{
|
|||
if (local.progress <= 0) {
|
||||
const res = startImport({
|
||||
list: local.data,
|
||||
task: async (e) => {
|
||||
task: async (e, index) => {
|
||||
if (typeof task === "function") {
|
||||
const result = await task({data: e, excel});
|
||||
const result = await task({data: e, excel, index, list: local.data, render: local.render});
|
||||
if (typeof result === "boolean") {
|
||||
if (!result) {
|
||||
local.recap.failed.push(e);
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ export const TableList: FC<TableListProp> = ({
|
|||
reloading: null as any,
|
||||
reload: (arg?: { toast: boolean }) => {
|
||||
if (local.reloading) return local.reloading;
|
||||
|
||||
local.reloading = new Promise<void>(async (done) => {
|
||||
let should_toast = true;
|
||||
if (arg?.toast === false) should_toast = false;
|
||||
|
|
@ -217,101 +218,99 @@ export const TableList: FC<TableListProp> = ({
|
|||
}
|
||||
|
||||
if (md) {
|
||||
if (md.header.loading) {
|
||||
await new Promise<void>((resolve) => {
|
||||
const ival = setInterval(() => {
|
||||
if (!md.header.loading) {
|
||||
clearInterval(ival);
|
||||
resolve();
|
||||
await new Promise<void>((resolve) => {
|
||||
const ival = setInterval(() => {
|
||||
if (!md.header.loading) {
|
||||
clearInterval(ival);
|
||||
resolve();
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
if (Array.isArray(md?.params?.links) && md?.params?.links?.length) {
|
||||
const last = md.params.links[md.params.links.length - 1];
|
||||
|
||||
if (last && last.where) {
|
||||
if ((last.name && last.name === md.name) || !last.name) {
|
||||
for (const [k, v] of Object.entries(last.where)) {
|
||||
where[k] = v;
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
const last = md.params.links[md.params.links.length - 1];
|
||||
|
||||
if (last && last.where) {
|
||||
if ((last.name && last.name === md.name) || !last.name) {
|
||||
for (const [k, v] of Object.entries(last.where)) {
|
||||
where[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_prasi_events("tablelist", "where", [__props?.gen__table, where]);
|
||||
|
||||
call_prasi_events("tablelist", "where", [
|
||||
__props?.gen__table,
|
||||
where,
|
||||
]);
|
||||
const load_args: any = {
|
||||
async reload() {},
|
||||
orderBy,
|
||||
where,
|
||||
paging: {
|
||||
take: local.paging.take > 0 ? local.paging.take : undefined,
|
||||
skip: local.paging.skip,
|
||||
},
|
||||
};
|
||||
|
||||
const load_args: any = {
|
||||
async reload() {},
|
||||
orderBy,
|
||||
where,
|
||||
paging: {
|
||||
take: local.paging.take > 0 ? local.paging.take : undefined,
|
||||
skip: local.paging.skip,
|
||||
},
|
||||
};
|
||||
|
||||
if (id_parent) {
|
||||
load_args.paging = {};
|
||||
}
|
||||
const result = on_load({ ...load_args, mode: "query" });
|
||||
const callback = (data: any[]) => {
|
||||
if (
|
||||
id_parent ||
|
||||
!local.paging ||
|
||||
(local.paging && !local.paging.take) ||
|
||||
local.paging.skip === 0
|
||||
) {
|
||||
local.data = data;
|
||||
} else {
|
||||
local.data = [...local.data, ...data];
|
||||
}
|
||||
|
||||
local.paging.last_length = local.data.length;
|
||||
|
||||
local.status = "ready";
|
||||
local.reloading = null;
|
||||
local.render();
|
||||
|
||||
done();
|
||||
setTimeout(() => {
|
||||
if (
|
||||
local.grid_ref &&
|
||||
!id_parent &&
|
||||
(paging !== undefined || paging)
|
||||
) {
|
||||
local.paging.scroll(local.grid_ref);
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
if (result instanceof Promise) {
|
||||
(async () => {
|
||||
try {
|
||||
callback(await result);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
local.status = "error";
|
||||
toast.dismiss();
|
||||
toast.error(
|
||||
<div className="c-flex c-text-red-600 c-items-center">
|
||||
<AlertTriangle className="c-h-4 c-w-4 c-mr-1" />
|
||||
Failed to load data
|
||||
</div>,
|
||||
{
|
||||
dismissible: true,
|
||||
className: css`
|
||||
background: #ffecec;
|
||||
border: 2px solid red;
|
||||
`,
|
||||
}
|
||||
);
|
||||
}
|
||||
})();
|
||||
} else callback(result);
|
||||
if (id_parent) {
|
||||
load_args.paging = {};
|
||||
}
|
||||
const result = on_load({ ...load_args, mode: "query" });
|
||||
const callback = (data: any[]) => {
|
||||
if (
|
||||
id_parent ||
|
||||
!local.paging ||
|
||||
(local.paging && !local.paging.take) ||
|
||||
local.paging.skip === 0
|
||||
) {
|
||||
local.data = data;
|
||||
} else {
|
||||
local.data = [...local.data, ...data];
|
||||
}
|
||||
|
||||
local.paging.last_length = local.data.length;
|
||||
|
||||
local.status = "ready";
|
||||
local.reloading = null;
|
||||
local.render();
|
||||
|
||||
done();
|
||||
setTimeout(() => {
|
||||
if (
|
||||
local.grid_ref &&
|
||||
!id_parent &&
|
||||
(paging !== undefined || paging)
|
||||
) {
|
||||
local.paging.scroll(local.grid_ref);
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
if (result instanceof Promise) {
|
||||
(async () => {
|
||||
try {
|
||||
callback(await result);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
local.status = "error";
|
||||
toast.dismiss();
|
||||
toast.error(
|
||||
<div className="c-flex c-text-red-600 c-items-center">
|
||||
<AlertTriangle className="c-h-4 c-w-4 c-mr-1" />
|
||||
Failed to load data
|
||||
</div>,
|
||||
{
|
||||
dismissible: true,
|
||||
className: css`
|
||||
background: #ffecec;
|
||||
border: 2px solid red;
|
||||
`,
|
||||
}
|
||||
);
|
||||
}
|
||||
})();
|
||||
} else callback(result);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return local.reloading;
|
||||
|
|
@ -557,7 +556,7 @@ export const TableList: FC<TableListProp> = ({
|
|||
|
||||
if (typeof local.data === "string") {
|
||||
console.error(local.data);
|
||||
local.data = []
|
||||
local.data = [];
|
||||
}
|
||||
|
||||
if (isEditor) {
|
||||
|
|
@ -579,163 +578,49 @@ export const TableList: FC<TableListProp> = ({
|
|||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (childs.length && isCheckbox) {
|
||||
columns.push({
|
||||
key: SELECT_COLUMN_KEY,
|
||||
name: "",
|
||||
width: 35,
|
||||
minWidth: 35,
|
||||
maxWidth: 35,
|
||||
resizable: false,
|
||||
sortable: false,
|
||||
frozen: true,
|
||||
renderHeaderCell(props) {
|
||||
return <input type="checkbox" onChange={headerCheckboxClick} />;
|
||||
},
|
||||
renderCell(props) {
|
||||
// digunakan untuk mengecek apakah local selected rows memiliki pk dari props.row.id
|
||||
const isChecked = local.selectedRows.some(
|
||||
(checked) => checked.pk === props.row.id
|
||||
);
|
||||
return (
|
||||
<div
|
||||
onClick={checkboxClick(props.row.id)}
|
||||
className={cx(
|
||||
css`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`,
|
||||
"c-flex c-items-center c-justify-center"
|
||||
)}
|
||||
>
|
||||
<input
|
||||
className="c-pointer-events-none"
|
||||
type="checkbox"
|
||||
checked={isChecked}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
headerCellClass: selectCellClassname,
|
||||
cellClass: selectCellClassname,
|
||||
});
|
||||
}
|
||||
|
||||
let first = true;
|
||||
for (const child of childs) {
|
||||
let key = getProp(child, "name", {});
|
||||
const name = getProp(child, "title", "");
|
||||
const type = getProp(child, "type", "");
|
||||
const width = parseInt(getProp(child, "width", {}));
|
||||
if (type === "checkbox") {
|
||||
columns.push({
|
||||
key,
|
||||
name,
|
||||
width: 35,
|
||||
minWidth: 45,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
frozen: true,
|
||||
renderHeaderCell(props) {
|
||||
return (
|
||||
<div>
|
||||
{/* <CheckboxList value={false} on_click={on_click} /> */}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
renderCell(props) {
|
||||
if (typeof render_col === "function")
|
||||
return render_col({
|
||||
props,
|
||||
tbl: local,
|
||||
child,
|
||||
});
|
||||
const sort = getProp(child, "sortir", "");
|
||||
let show = getProp(child, "show", "");
|
||||
if (typeof show === "function") {
|
||||
show = show();
|
||||
if (typeof show === "object" && show instanceof Promise) {
|
||||
show.then((e) => {
|
||||
show = e;
|
||||
});
|
||||
}
|
||||
}
|
||||
show = show === "n" ? false : show;
|
||||
if (show) {
|
||||
const type = getProp(child, "type", "");
|
||||
const width = parseInt(getProp(child, "width", {}));
|
||||
if (type === "checkbox") {
|
||||
columns.push({
|
||||
key,
|
||||
name,
|
||||
width: 35,
|
||||
minWidth: 45,
|
||||
resizable: true,
|
||||
sortable: sort === "n" ? false : true,
|
||||
frozen: true,
|
||||
renderHeaderCell(props) {
|
||||
return (
|
||||
<div>
|
||||
{/* <CheckboxList value={false} on_click={on_click} /> */}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
renderCell(props) {
|
||||
if (typeof render_col === "function")
|
||||
return render_col({
|
||||
props,
|
||||
tbl: local,
|
||||
child,
|
||||
});
|
||||
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: props.column.key,
|
||||
value: get(props.row, props.column.key),
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={local.data}
|
||||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
columns.push({
|
||||
key,
|
||||
name,
|
||||
width: width > 0 ? width : undefined,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
renderCell(props) {
|
||||
if (typeof render_col === "function")
|
||||
return render_col({
|
||||
props,
|
||||
tbl: local,
|
||||
child,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{isTree && local.firstKey === key && local.pk && (
|
||||
<div
|
||||
className={cx(
|
||||
css`
|
||||
padding-left: ${3 + props.row.__depth * 8}px;
|
||||
`,
|
||||
"c-flex c-items-center c-cursor-pointer"
|
||||
)}
|
||||
onClick={(e) => {
|
||||
if (!local.pk) return;
|
||||
if (props?.row?.__children?.length > 0) {
|
||||
e.stopPropagation();
|
||||
if (!local.collapsed.has(props.row?.[local.pk.name])) {
|
||||
local.collapsed.add(props.row?.[local.pk.name]);
|
||||
} else {
|
||||
local.collapsed.delete(props.row?.[local.pk.name]);
|
||||
}
|
||||
local.render();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
css`
|
||||
width: 16px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{props.row?.__children?.length > 0 && (
|
||||
<>
|
||||
{local.collapsed.has(props.row?.[local.pk.name]) ? (
|
||||
<ChevronRight size={16} />
|
||||
) : (
|
||||
<ChevronDown size={16} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{props.row?.__parent &&
|
||||
(props.row?.__children || []).length === 0 && (
|
||||
<div
|
||||
className={cx(
|
||||
" c-border-l c-border-b c-border-black c-w-[10px] c-h-[15px]",
|
||||
css`
|
||||
margin-top: -10px;
|
||||
`
|
||||
)}
|
||||
></div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
return (
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
|
|
@ -748,14 +633,160 @@ export const TableList: FC<TableListProp> = ({
|
|||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
</>
|
||||
);
|
||||
},
|
||||
});
|
||||
);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
columns.push({
|
||||
key,
|
||||
name,
|
||||
width: width > 0 ? width : undefined,
|
||||
resizable: true,
|
||||
sortable: sort === "n" ? false : true,
|
||||
renderHeaderCell(props) {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-row flex-grow items-center"
|
||||
onClick={() => {
|
||||
const msg = `The ${props?.column?.name} column cannot be sorted!`;
|
||||
if (!props?.column?.sortable) {
|
||||
toast.dismiss();
|
||||
toast.error(
|
||||
<div className="c-flex c-text-red-600 c-items-center">
|
||||
<AlertTriangle className="c-h-4 c-w-4 c-mr-1" />
|
||||
{msg}
|
||||
</div>,
|
||||
{
|
||||
dismissible: true,
|
||||
className: css`
|
||||
background: #ffecec;
|
||||
border: 2px solid red;
|
||||
`,
|
||||
}
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{props?.column?.name}
|
||||
{props.sortDirection ? (
|
||||
<>
|
||||
{" "}
|
||||
<div className="px-1">
|
||||
{props.sortDirection === "ASC" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12.53 7.97a.75.75 0 0 0-1.06 0l-7 7A.75.75 0 0 0 5 16.25h14a.75.75 0 0 0 .53-1.28z"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5 7.75a.75.75 0 0 0-.53 1.28l7 7a.75.75 0 0 0 1.06 0l7-7A.75.75 0 0 0 19 7.75z"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
renderCell(props) {
|
||||
if (typeof render_col === "function")
|
||||
return render_col({
|
||||
props,
|
||||
tbl: local,
|
||||
child,
|
||||
});
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
local.firstKey = key;
|
||||
return (
|
||||
<>
|
||||
{isTree && local.firstKey === key && local.pk && (
|
||||
<div
|
||||
className={cx(
|
||||
css`
|
||||
padding-left: ${3 + props.row.__depth * 8}px;
|
||||
`,
|
||||
"c-flex c-items-center c-cursor-pointer"
|
||||
)}
|
||||
onClick={(e) => {
|
||||
if (!local.pk) return;
|
||||
if (props?.row?.__children?.length > 0) {
|
||||
e.stopPropagation();
|
||||
if (!local.collapsed.has(props.row?.[local.pk.name])) {
|
||||
local.collapsed.add(props.row?.[local.pk.name]);
|
||||
} else {
|
||||
local.collapsed.delete(props.row?.[local.pk.name]);
|
||||
}
|
||||
local.render();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
css`
|
||||
width: 16px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{props.row?.__children?.length > 0 && (
|
||||
<>
|
||||
{local.collapsed.has(props.row?.[local.pk.name]) ? (
|
||||
<ChevronRight size={16} />
|
||||
) : (
|
||||
<ChevronDown size={16} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{props.row?.__parent &&
|
||||
(props.row?.__children || []).length === 0 && (
|
||||
<div
|
||||
className={cx(
|
||||
" c-border-l c-border-b c-border-black c-w-[10px] c-h-[15px] rows",
|
||||
css`
|
||||
margin-top: -10px;
|
||||
`
|
||||
)}
|
||||
></div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<PassProp
|
||||
idx={props.rowIdx}
|
||||
row={props.row}
|
||||
col={{
|
||||
name: props.column.key,
|
||||
value: get(props.row, props.column.key),
|
||||
depth: props.row.__depth || 0,
|
||||
}}
|
||||
rows={local.data}
|
||||
>
|
||||
{child}
|
||||
</PassProp>
|
||||
</>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
local.firstKey = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,9 +25,12 @@ export const generateTableList = async (
|
|||
)[];
|
||||
let pk = "";
|
||||
let pks: Record<string, string> = {};
|
||||
// console.log(raw_fields)
|
||||
const fields = parseGenField(raw_fields);
|
||||
// convert ke bahasa prisma untuk select
|
||||
const res = generateSelect(fields);
|
||||
console.log({res})
|
||||
console.log({fields})
|
||||
pk = res.pk;
|
||||
const select = res.select as any;
|
||||
if (!pk) {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ idx: any;
|
|||
}
|
||||
`,
|
||||
});
|
||||
|
||||
tab_master?.edit.setChilds([
|
||||
{
|
||||
type: "item",
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ export const SheetCn: FC<{
|
|||
header: string;
|
||||
open: string;
|
||||
close?: string;
|
||||
mode?: "full" | "normal";
|
||||
mode?: "full" | "normal" | "1/3";
|
||||
direction?: "left" | "right" | "bottom" | "top";
|
||||
deps?: any;
|
||||
_item?: PrasiItem;
|
||||
onInit?: (e: any) => void;
|
||||
}> = ({
|
||||
child,
|
||||
PassProp,
|
||||
|
|
@ -35,10 +37,13 @@ export const SheetCn: FC<{
|
|||
close,
|
||||
mode,
|
||||
direction,
|
||||
deps
|
||||
deps,
|
||||
_item,
|
||||
onInit,
|
||||
}) => {
|
||||
const local = useLocal({
|
||||
open: false,
|
||||
data: null as any,
|
||||
});
|
||||
useEffect(() => {
|
||||
if (isEditor) {
|
||||
|
|
@ -47,6 +52,25 @@ export const SheetCn: FC<{
|
|||
local.open = op;
|
||||
local.render();
|
||||
}
|
||||
} else {
|
||||
console.log(typeof onInit)
|
||||
if (typeof onInit === "function") {
|
||||
onInit({
|
||||
data: local,
|
||||
deps,
|
||||
open: () => {
|
||||
local.open = true;
|
||||
local.render();
|
||||
setTimeout(() => {
|
||||
document.body.style.pointerEvents = "auto";
|
||||
}, 1000);
|
||||
},
|
||||
close: () => {
|
||||
local.open = false;
|
||||
local.render();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [open]);
|
||||
return (
|
||||
|
|
@ -55,6 +79,7 @@ export const SheetCn: FC<{
|
|||
<div {...props} className={cx(props.className, "")}>
|
||||
<PassProp
|
||||
sheet={{
|
||||
data: local,
|
||||
deps,
|
||||
open: () => {
|
||||
local.open = true;
|
||||
|
|
@ -89,57 +114,79 @@ export const SheetCn: FC<{
|
|||
<SheetContent
|
||||
side={direction}
|
||||
className={cx(
|
||||
mode === "full" ? "c-w-screen" : "sm:s-max-w-[425px]",
|
||||
mode === "1/3"
|
||||
? css`
|
||||
max-width: 500px !important;
|
||||
`
|
||||
: mode === "full"
|
||||
? "c-w-screen"
|
||||
: "sm:s-max-w-[425px]",
|
||||
css`
|
||||
z-index: 2;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{close !== "n" ? (
|
||||
<SheetPrimitive.Close
|
||||
onClick={() => {
|
||||
local.open = false;
|
||||
local.render();
|
||||
}}
|
||||
className={cx(
|
||||
"c-absolute c-right-4 c-top-4 c-rounded-sm c-opacity-70 c-ring-offset-background c-transition-opacity hover:c-opacity-100 focus:c-outline-none focus:c-ring-2 focus:c-ring-ring focus:c-ring-offset-2 disabled:c-pointer-events-none data-[state=open]:c-bg-accent data-[state=open]:c-text-muted-foreground",
|
||||
css`
|
||||
right: 1rem;
|
||||
z-index: 99;
|
||||
`
|
||||
)}
|
||||
>
|
||||
<X className="c-h-4 c-w-4" />
|
||||
<span className="c-sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{header !== "" && header ? (
|
||||
<SheetHeader
|
||||
className={cx(
|
||||
css`
|
||||
padding: 0px 0px 0px 10px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
<SheetTitle>{header}</SheetTitle>
|
||||
</SheetHeader>
|
||||
) : (
|
||||
<>
|
||||
<SheetHeader
|
||||
className={cx(
|
||||
css`
|
||||
padding: 0px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
<SheetTitle></SheetTitle>
|
||||
</SheetHeader></>
|
||||
)}
|
||||
<div className="c-relative">
|
||||
{close !== "n" ? (
|
||||
<SheetPrimitive.Close
|
||||
onClick={() => {
|
||||
local.open = false;
|
||||
local.render();
|
||||
}}
|
||||
className={cx(
|
||||
"c-absolute c-right-4 c-rounded-sm c-opacity-70 c-ring-offset-background c-transition-opacity hover:c-opacity-100 focus:c-outline-none focus:c-ring-2 focus:c-ring-ring focus:c-ring-offset-2 disabled:c-pointer-events-none data-[state=open]:c-bg-accent data-[state=open]:c-text-muted-foreground",
|
||||
css`
|
||||
right: 1rem;
|
||||
z-index: 99;
|
||||
transform: translateY(50%);
|
||||
`
|
||||
)}
|
||||
>
|
||||
<X className="c-h-4 c-w-4" />
|
||||
<span className="c-sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{header !== "" && header ? (
|
||||
<SheetHeader
|
||||
className={cx(
|
||||
"c-text-base",
|
||||
css`
|
||||
padding: 0px 0px 0px 10px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
<SheetTitle
|
||||
className={cx(
|
||||
"c-text-base",
|
||||
css`
|
||||
font-size: 1rem !important;
|
||||
line-height: 1.5rem !important;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{header}
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
) : (
|
||||
<>
|
||||
<SheetHeader
|
||||
className={cx(
|
||||
css`
|
||||
padding: 0px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
<SheetTitle></SheetTitle>
|
||||
</SheetHeader>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<PassProp
|
||||
sheet={{
|
||||
data: local,
|
||||
deps,
|
||||
open: () => {
|
||||
local.open = true;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
import { useLocal } from "lib/utils/use-local";
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
||||
import { X } from "lucide-react";
|
||||
import { FC, useEffect } from "react";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "lib/comps/ui/carousel";
|
||||
|
||||
export const Slide: FC<{
|
||||
child: any;
|
||||
PassProp: any;
|
||||
props: any;
|
||||
mode?: "full" | "normal";
|
||||
direction?: "vertical" | "horizontal";
|
||||
deps?: any;
|
||||
_item?: PrasiItem;
|
||||
data: any;
|
||||
}> = ({ child, PassProp, props, mode, direction, deps, _item, data }) => {
|
||||
return (
|
||||
<Carousel className="c-flex c-flex-row c-flex-grow c-flex-1 ">
|
||||
<CarouselContent>
|
||||
{Array.isArray(data) ? (
|
||||
<>
|
||||
{data.map((e, idx) => {
|
||||
return (
|
||||
<CarouselItem>
|
||||
<PassProp item={e} idx={idx} slide={{ deps }}>
|
||||
{child}
|
||||
</PassProp>
|
||||
</CarouselItem>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
);
|
||||
};
|
||||
|
|
@ -2,9 +2,10 @@ import { useLocal } from "lib/utils/use-local";
|
|||
import get from "lodash.get";
|
||||
import { FC, ReactNode, useEffect } from "react";
|
||||
import { PTLocalInternal, PTProp } from "../utils/typings";
|
||||
export const PanelTab: FC<PTProp> = ({ header, body, tab, PassProp, item }) => {
|
||||
export const PanelTab: FC<PTProp> = ({ header, body, tab, PassProp, item, deps }) => {
|
||||
const local = useLocal<PTLocalInternal>({
|
||||
mode: "" as any,
|
||||
deps
|
||||
});
|
||||
useEffect(() => {
|
||||
local.mode = tab;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ export type PTProp = {
|
|||
PassProp: any;
|
||||
item: PrasiItem;
|
||||
pt: PTLocalInternal;
|
||||
deps?: any;
|
||||
};
|
||||
|
||||
export type PTLocalInternal = {
|
||||
mode: string;
|
||||
deps?: any
|
||||
};
|
||||
export type PTLocal = PTLocalInternal & { render: (force?: boolean) => void };
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
"use client"
|
||||
|
||||
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
|
||||
|
||||
const AspectRatio = AspectRatioPrimitive.Root
|
||||
|
||||
export { AspectRatio }
|
||||
|
|
@ -155,7 +155,7 @@ const CarouselContent = React.forwardRef<
|
|||
const { carouselRef, orientation } = useCarousel()
|
||||
|
||||
return (
|
||||
<div ref={carouselRef} className="c-overflow-hidden">
|
||||
<div ref={carouselRef} className="c-overflow-hidden c-w-full c-flex-grow c-flex-1">
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ const SheetContent = React.forwardRef<
|
|||
<SheetPortal>
|
||||
<SheetPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(sheetVariants({ side }), className)}
|
||||
className={cn(sheetVariants({ side }), className, "sheet-content")}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
|
|
@ -102,7 +102,7 @@ const SheetTitle = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("c-text-lg c-font-semibold c-text-foreground", className)}
|
||||
className={cn("c-py-2 c-text-lg c-font-semibold c-text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export const Typeahead: FC<{
|
|||
disabled?: boolean;
|
||||
mode?: "multi" | "single";
|
||||
note?: string;
|
||||
disabledSearch?: boolean;
|
||||
}> = ({
|
||||
value,
|
||||
note,
|
||||
|
|
@ -41,6 +42,7 @@ export const Typeahead: FC<{
|
|||
onChange,
|
||||
className,
|
||||
popupClassName,
|
||||
disabledSearch
|
||||
}) => {
|
||||
const local = useLocal({
|
||||
value: [] as string[],
|
||||
|
|
@ -440,13 +442,8 @@ export const Typeahead: FC<{
|
|||
return false;
|
||||
}}
|
||||
>
|
||||
<input
|
||||
placeholder={
|
||||
local.mode === "multi" ? placeholder : valueLabel[0]?.label
|
||||
}
|
||||
type="text"
|
||||
ref={input}
|
||||
value={inputval}
|
||||
<div
|
||||
className="single c-flex-1 c-flex-grow c-flex c-flex-row c-cursor-pointer c-z-99"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!disabled) {
|
||||
|
|
@ -459,75 +456,44 @@ export const Typeahead: FC<{
|
|||
}
|
||||
|
||||
if (local.mode === "single") {
|
||||
e.currentTarget.select();
|
||||
if (input && input.current) input.current.select();
|
||||
}
|
||||
}
|
||||
}}
|
||||
onChange={async (e) => {
|
||||
const val = e.currentTarget.value;
|
||||
if (!local.open) {
|
||||
local.open = true;
|
||||
>
|
||||
<input
|
||||
placeholder={
|
||||
local.mode === "multi" ? placeholder : valueLabel[0]?.label
|
||||
}
|
||||
type="text"
|
||||
ref={input}
|
||||
value={inputval}
|
||||
onChange={async (e) => {
|
||||
const val = e.currentTarget.value;
|
||||
if (!local.open) {
|
||||
local.open = true;
|
||||
}
|
||||
|
||||
local.search.input = val;
|
||||
local.render();
|
||||
local.search.input = val;
|
||||
local.render();
|
||||
|
||||
if (local.search.promise) {
|
||||
await local.search.promise;
|
||||
}
|
||||
if (local.search.promise) {
|
||||
await local.search.promise;
|
||||
}
|
||||
|
||||
local.search.searching = true;
|
||||
local.render();
|
||||
local.search.searching = true;
|
||||
local.render();
|
||||
|
||||
if (local.search.searching) {
|
||||
if (local.local_search) {
|
||||
if (!local.loaded) {
|
||||
await loadOptions();
|
||||
}
|
||||
const search = local.search.input.toLowerCase();
|
||||
if (search) {
|
||||
local.search.result = options.filter((e) =>
|
||||
e.label.toLowerCase().includes(search)
|
||||
);
|
||||
|
||||
if (
|
||||
local.search.result.length > 0 &&
|
||||
!local.search.result.find(
|
||||
(e) => e.value === local.select?.value
|
||||
)
|
||||
) {
|
||||
local.select = local.search.result[0];
|
||||
if (local.search.searching) {
|
||||
if (local.local_search) {
|
||||
if (!local.loaded) {
|
||||
await loadOptions();
|
||||
}
|
||||
} else {
|
||||
local.search.result = null;
|
||||
}
|
||||
local.search.searching = false;
|
||||
local.render();
|
||||
} else {
|
||||
clearTimeout(local.search.timeout);
|
||||
local.search.timeout = setTimeout(async () => {
|
||||
const result = options_fn?.({
|
||||
search: local.search.input,
|
||||
existing: options,
|
||||
});
|
||||
if (result) {
|
||||
if (result instanceof Promise) {
|
||||
local.search.promise = result;
|
||||
local.search.result = (await result).map((item) => {
|
||||
if (typeof item === "string")
|
||||
return { value: item, label: item };
|
||||
return item;
|
||||
});
|
||||
local.search.searching = false;
|
||||
local.search.promise = null;
|
||||
} else {
|
||||
local.search.result = result.map((item) => {
|
||||
if (typeof item === "string")
|
||||
return { value: item, label: item };
|
||||
return item;
|
||||
});
|
||||
local.search.searching = false;
|
||||
}
|
||||
const search = local.search.input.toLowerCase();
|
||||
if (search) {
|
||||
local.search.result = options.filter((e) =>
|
||||
e.label.toLowerCase().includes(search)
|
||||
);
|
||||
|
||||
if (
|
||||
local.search.result.length > 0 &&
|
||||
|
|
@ -537,21 +503,64 @@ export const Typeahead: FC<{
|
|||
) {
|
||||
local.select = local.search.result[0];
|
||||
}
|
||||
|
||||
local.render();
|
||||
} else {
|
||||
local.search.result = null;
|
||||
}
|
||||
}, 100);
|
||||
local.search.searching = false;
|
||||
local.render();
|
||||
} else {
|
||||
clearTimeout(local.search.timeout);
|
||||
local.search.timeout = setTimeout(async () => {
|
||||
const result = options_fn?.({
|
||||
search: local.search.input,
|
||||
existing: options,
|
||||
});
|
||||
if (result) {
|
||||
if (result instanceof Promise) {
|
||||
local.search.promise = result;
|
||||
local.search.result = (await result).map((item) => {
|
||||
if (typeof item === "string")
|
||||
return { value: item, label: item };
|
||||
return item;
|
||||
});
|
||||
local.search.searching = false;
|
||||
local.search.promise = null;
|
||||
} else {
|
||||
local.search.result = result.map((item) => {
|
||||
if (typeof item === "string")
|
||||
return { value: item, label: item };
|
||||
return item;
|
||||
});
|
||||
local.search.searching = false;
|
||||
}
|
||||
|
||||
if (
|
||||
local.search.result.length > 0 &&
|
||||
!local.search.result.find(
|
||||
(e) => e.value === local.select?.value
|
||||
)
|
||||
) {
|
||||
local.select = local.search.result[0];
|
||||
}
|
||||
|
||||
local.render();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
disabled={disabled}
|
||||
spellCheck={false}
|
||||
className={cx(
|
||||
"c-flex-1 c-mb-2 c-outline-none c-bg-transparent",
|
||||
local.mode === "single" ? "c-cursor-pointer" : ""
|
||||
)}
|
||||
onKeyDown={keydown}
|
||||
/>
|
||||
}}
|
||||
disabled={!disabled ? disabledSearch : disabled}
|
||||
spellCheck={false}
|
||||
className={cx(
|
||||
"c-flex-1 c-mb-2 c-outline-none c-bg-transparent",
|
||||
local.mode === "single" ? "c-cursor-pointer" : ""
|
||||
)}
|
||||
style={{
|
||||
pointerEvents: disabledSearch ? "none" : "auto", // Mencegah input menangkap klik saat disabled
|
||||
}}
|
||||
onKeyDown={keydown}
|
||||
/>
|
||||
</div>
|
||||
</TypeaheadOptions>
|
||||
{local.mode === "single" && (
|
||||
<div
|
||||
|
|
|
|||
18
exports.tsx
18
exports.tsx
|
|
@ -20,9 +20,9 @@ export const Typeahead = lazify(
|
|||
);
|
||||
|
||||
/** Master - Detail - List - Form */
|
||||
export const MasterDetail = lazify(
|
||||
async () => (await import("lib/comps/md/MasterDetail")).MasterDetail
|
||||
);
|
||||
// export const MasterDetail = lazify(
|
||||
// async () => (await import("lib/comps/md/MasterDetail")).MasterDetail
|
||||
// );
|
||||
export const MDRenderMaster = lazify(
|
||||
async () => (await import("lib/comps/md/parts/MDMaster")).MDRenderMaster
|
||||
);
|
||||
|
|
@ -107,6 +107,13 @@ export const Pop = lazify(
|
|||
async () => (await import("lib/comps/dialog/Dialog")).Pop
|
||||
);
|
||||
|
||||
export const Slide = lazify(
|
||||
async () => (await import("lib/comps/slide/Slide")).Slide
|
||||
);
|
||||
|
||||
export const AspectRatio = lazify(
|
||||
async () => (await import("lib/comps/ui/aspect-ratio")).AspectRatio
|
||||
);
|
||||
export const Import = lazify(
|
||||
async () => (await import("lib/comps/import/Import")).Import
|
||||
);
|
||||
|
|
@ -134,11 +141,12 @@ export { kvToJSON } from "./utils/kv-to-json";
|
|||
export { overrideNav } from "./utils/override-nav";
|
||||
export { bulk_query } from "./utils/bulk-query";
|
||||
export { get_user } from "./utils/get_user";
|
||||
export { range_date } from "./utils/ranged_date";
|
||||
export const _sum = sum;
|
||||
export const _get = __get;
|
||||
|
||||
/** Generator */
|
||||
export { generateFilter as genereteFilter } from "lib/comps/filter/gen/gen-filter";
|
||||
export { generateFilter as generateFilter } from "lib/comps/filter/gen/gen-filter";
|
||||
export { generateRelation } from "lib/comps/form/gen/gen-rel";
|
||||
export { genTableEdit } from "lib/comps/form/gen/gen-table-edit";
|
||||
export { generateMasterDetail } from "lib/comps/md/gen/md-gen";
|
||||
|
|
@ -146,7 +154,7 @@ export { parseGenField } from "lib/gen/utils";
|
|||
|
||||
/** ETC */
|
||||
export { filterModifier } from "lib/comps/filter/utils/filter-modifier";
|
||||
export { generateField } from "lib/comps/form/gen/gen-field";
|
||||
// export { generateField } from "lib/comps/form/gen/gen-field";
|
||||
export { generateForm } from "lib/comps/form/gen/gen-form";
|
||||
export { validate as validateField } from "lib/comps/form/utils/validate";
|
||||
export { sortTree, treePrefix } from "lib/comps/list/utils/sort-tree";
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export const logout = (url_login?: string) => {
|
|||
if (isEditor) return;
|
||||
if (typeof get(w, "user") === "object") {
|
||||
w.user = null;
|
||||
localStorage.removeItem("expiry_date");
|
||||
}
|
||||
|
||||
let id_site = "";
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ export const registerSession = (session: RG) => {
|
|||
}
|
||||
|
||||
localStorage.setItem("user" + id_site, JSON.stringify(data));
|
||||
localStorage.setItem(
|
||||
"expiry_date",
|
||||
data.expired ? data.expired?.format("YYYY-MM-DD HH:mm:ss") : ""
|
||||
);
|
||||
w.user = session.data;
|
||||
w.user.role = session.role;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ type LYTChild = {
|
|||
tablet?: ReactNode;
|
||||
child?: ReactNode;
|
||||
default_layout: ReactNode;
|
||||
exception?: Array<string>;
|
||||
exception?: ((path: string) => boolean) | Array<string>;
|
||||
blank_layout: ReactNode;
|
||||
login_url: string;
|
||||
PassProp: any;
|
||||
|
|
@ -66,28 +66,32 @@ export const Layout: FC<LYTChild> = (props) => {
|
|||
}, []);
|
||||
|
||||
initResponsive();
|
||||
const path = getPathname();
|
||||
const path = getPathname({ hash: true });
|
||||
const no_layout = props.exception;
|
||||
|
||||
overrideNav({ local });
|
||||
|
||||
if (
|
||||
!isEditor &&
|
||||
Array.isArray(no_layout) &&
|
||||
no_layout.find((rule) => wildcardMatch(path, rule))
|
||||
(typeof no_layout === "function"
|
||||
? no_layout!(path)
|
||||
: Array.isArray(no_layout) &&
|
||||
no_layout.find((rule) => wildcardMatch(path, rule)))
|
||||
) {
|
||||
return <>{props.blank_layout}</>;
|
||||
} else {
|
||||
if (!w.user) {
|
||||
local.loading = true;
|
||||
loadSession(props.login_url || "/auth/login");
|
||||
isMobile
|
||||
? loadSession("/m/auth/login")
|
||||
: loadSession(props.login_url || "/auth/login");
|
||||
|
||||
local.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (path === props.login_url) return props.blank_layout;
|
||||
if (!w.user && !isEditor) {
|
||||
if (!w.user && !isEditor && !isMobile) {
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
export const range_date = (param: { data: any, name: any }) => {
|
||||
const {data, name} = param;
|
||||
let result = null as any;
|
||||
Object.keys(data).map((e) => {
|
||||
if (["lte", "gte", "gt", "lt"].includes(e)) {
|
||||
if (data?.[e] instanceof Date) {
|
||||
const today = data?.[e];
|
||||
const day = new Date(today);
|
||||
if (["lte", "lt"].includes(e)) {
|
||||
day.setHours(23, 59, 59, 999); // Mengatur waktu ke 23:59:59
|
||||
} else if (["gte", "gt"].includes(e)) {
|
||||
day.setHours(0, 0, 0, 0); // Mengatur waktu ke 00:00:
|
||||
}
|
||||
result = {
|
||||
...result,
|
||||
[e]: day,
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
if (result)
|
||||
return {
|
||||
[name]: result,
|
||||
};
|
||||
return result;
|
||||
|
||||
};
|
||||
Loading…
Reference in New Issue