fixing
This commit is contained in:
parent
cd80bd07cb
commit
aea083c0ea
|
|
@ -119,8 +119,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
const [calendarEvents, setCalendarEvents] = useState<CalendarEvent[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const t = useTranslations("CalendarApp");
|
||||
|
||||
// Modal states
|
||||
const [sheetOpen, setSheetOpen] = useState<boolean>(false);
|
||||
const [date, setDate] = useState<Date>(new Date());
|
||||
const [activeView, setActiveView] = useState("listYear");
|
||||
|
|
@ -132,7 +130,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
dayjs(new Date(Number(INITIAL_YEAR), Number(INITIAL_MONTH) - 1, 1))
|
||||
);
|
||||
|
||||
// Load events when view or month changes
|
||||
useEffect(() => {
|
||||
if (activeView === "listYear") {
|
||||
getYearlyEvents();
|
||||
|
|
@ -141,7 +138,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
}
|
||||
}, [activeView, selectedMonth]);
|
||||
|
||||
// Initialize selected categories
|
||||
useEffect(() => {
|
||||
if (categories?.length > 0) {
|
||||
setSelectedCategory(categories.map((c) => c.value));
|
||||
|
|
@ -162,11 +158,9 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// For monthly view, we need to extract events from the specific month
|
||||
const monthData = res?.data?.data;
|
||||
if (monthData) {
|
||||
const allEvents: CalendarEvent[] = [];
|
||||
// Map API data to the calendarEvents structure
|
||||
const events = monthData?.map((event: any) => ({
|
||||
id: event.id.toString(),
|
||||
title: event.title,
|
||||
|
|
@ -208,7 +202,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// The API already returns data organized by months
|
||||
const yearlyData = res?.data?.data;
|
||||
if (yearlyData) {
|
||||
setYearlyData(yearlyData);
|
||||
|
|
@ -221,7 +214,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
}
|
||||
};
|
||||
|
||||
// Filter events based on selected categories
|
||||
const filteredEvents = calendarEvents.filter((event) => {
|
||||
if (!selectedCategory.length) return false;
|
||||
console.log("Event category : ", selectedCategory);
|
||||
|
|
@ -231,7 +223,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
.map((val: string) => val.trim());
|
||||
|
||||
const allCategoryId = ["1", "2", "3", "4", "5"];
|
||||
// Cek apakah SEMUA validTypeIds ada di typeIdsInData
|
||||
const hasAllCategories = allCategoryId.every((categoryId) =>
|
||||
selectedCategory.includes(categoryId)
|
||||
);
|
||||
|
|
@ -242,7 +233,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
);
|
||||
});
|
||||
|
||||
// Event handlers
|
||||
const handleEventClick = (arg: any) => {
|
||||
setSelectedEventDate(null);
|
||||
setSelectedEventData(arg);
|
||||
|
|
@ -307,7 +297,6 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
wait().then(() => (document.body.style.pointerEvents = "auto"));
|
||||
};
|
||||
|
||||
// Utility functions
|
||||
const getEventColor = (type: EventType): string => {
|
||||
const typeSplit = type.split(",");
|
||||
const firstType = typeSplit[0] as EventType;
|
||||
|
|
|
|||
|
|
@ -234,7 +234,6 @@ const EventModal = ({
|
|||
|
||||
setWilayahPublish(wilayahState);
|
||||
|
||||
// Atur unit berdasarkan agendaType
|
||||
if (rawAgendaTypes.includes("2")) {
|
||||
setSelectedPolda(assignedToLevel);
|
||||
}
|
||||
|
|
@ -272,8 +271,6 @@ const EventModal = ({
|
|||
const toggleWilayah = (key: string) => {
|
||||
setWilayahPublish((prev: any) => {
|
||||
let newState = { ...prev };
|
||||
|
||||
// Jika key === semua dan sebelumnya belum aktif, aktifkan semua
|
||||
if (key === "semua") {
|
||||
const newChecked = !prev.semua;
|
||||
newState = {
|
||||
|
|
@ -294,11 +291,9 @@ const EventModal = ({
|
|||
return newState;
|
||||
}
|
||||
|
||||
// Jika key bukan "semua"
|
||||
newState[key] = !prev[key];
|
||||
newState.semua = false; // Uncheck "semua" jika yang dipilih adalah individu
|
||||
newState.semua = false;
|
||||
|
||||
// Hitung ulang agendaType berdasarkan pilihan
|
||||
const selectedKeys = Object.entries(newState)
|
||||
.filter(([k, v]) => v && k !== "semua")
|
||||
.map(([k]) => wilayahValueMap[k]);
|
||||
|
|
@ -348,8 +343,8 @@ const EventModal = ({
|
|||
id: detailData?.id,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
agendaType: agendaTypeList.join(","), // <-- ubah array jadi string
|
||||
assignedToLevel: assignedToLevelList.join(","), // <-- ubah array jadi string
|
||||
agendaType: agendaTypeList.join(","),
|
||||
assignedToLevel: assignedToLevelList.join(","),
|
||||
startDate: format(startDate, "yyyy-MM-dd"),
|
||||
endDate: format(endDate, "yyyy-MM-dd"),
|
||||
};
|
||||
|
|
@ -393,9 +388,9 @@ const EventModal = ({
|
|||
await uploadResumableFile(
|
||||
index,
|
||||
String(id),
|
||||
item, // Use .file to access the actual File object
|
||||
item,
|
||||
"4",
|
||||
"0" // Optional: Replace with actual duration if available
|
||||
"0"
|
||||
);
|
||||
});
|
||||
if (publish) {
|
||||
|
|
@ -466,28 +461,26 @@ const EventModal = ({
|
|||
const onRecordingStart = () => {
|
||||
setIsRecording(true);
|
||||
|
||||
// Start a timer that stops the recording after 2 minutes (120 seconds)
|
||||
const countdown = setInterval(() => {
|
||||
setTimer((prevTimer) => {
|
||||
if (prevTimer <= 1) {
|
||||
clearInterval(countdown); // Stop the timer when it reaches 0
|
||||
clearInterval(countdown);
|
||||
return 0;
|
||||
}
|
||||
return prevTimer - 1;
|
||||
});
|
||||
}, 1000); // Update every second
|
||||
}, 1000);
|
||||
|
||||
// Automatically stop recording after 2 minutes
|
||||
setTimeout(() => {
|
||||
if (isRecording) {
|
||||
handleStopRecording();
|
||||
}
|
||||
}, 120000); // Stop after 2 minutes (120,000 ms)
|
||||
}, 120000);
|
||||
};
|
||||
|
||||
const handleStopRecording = () => {
|
||||
setIsRecording(false);
|
||||
setTimer(120); // Reset the timer to 2 minutes for the next recording
|
||||
setTimer(120);
|
||||
};
|
||||
|
||||
const addAudioElement = (blob: Blob) => {
|
||||
|
|
@ -497,19 +490,16 @@ const EventModal = ({
|
|||
audio.controls = true;
|
||||
document.body.appendChild(audio);
|
||||
|
||||
// Convert Blob to File and add preview
|
||||
const fileWithPreview: FileWithPreview = Object.assign(
|
||||
new File([blob], "voiceNote.webm", { type: "audio/webm" }),
|
||||
{ preview: url }
|
||||
);
|
||||
|
||||
// Add to state
|
||||
setAudioFile(fileWithPreview);
|
||||
setAudioFiles((prev) => [...prev, fileWithPreview]);
|
||||
};
|
||||
|
||||
const handleDeleteAudio = () => {
|
||||
// Remove the audio file by setting state to null
|
||||
setAudioFile(null);
|
||||
const audioElements = document.querySelectorAll("audio");
|
||||
audioElements.forEach((audio) => audio.remove());
|
||||
|
|
@ -842,7 +832,7 @@ const EventModal = ({
|
|||
{wilayahPublish.polda && (
|
||||
<UnitMapping
|
||||
unit="Polda"
|
||||
isDetail={isDetailMode} // jika Anda punya kondisi detail
|
||||
isDetail={isDetailMode}
|
||||
initData={selectedPolda}
|
||||
sendDataToParent={(data: any) =>
|
||||
setSelectedPolda(data)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ export function UnitMapping(props: {
|
|||
? isAllSatkerChecked
|
||||
: isAllPolresChecked
|
||||
}
|
||||
disabled={isDetail}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
|
|
@ -139,6 +138,7 @@ export function UnitMapping(props: {
|
|||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<label htmlFor="all" className="text-sm text-black uppercase">
|
||||
SEMUA {unit}
|
||||
</label>
|
||||
|
|
@ -170,7 +170,6 @@ export function UnitMapping(props: {
|
|||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
disabled={isDetail}
|
||||
checked={field.value?.includes(String(item.id))}
|
||||
onCheckedChange={(checked) => {
|
||||
return checked
|
||||
|
|
|
|||
|
|
@ -62,11 +62,12 @@ const BlogTable = () => {
|
|||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [showData, setShowData] = React.useState("50");
|
||||
const [showData, setShowData] = React.useState("10");
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: Number(showData),
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
|
|
@ -143,14 +144,12 @@ const BlogTable = () => {
|
|||
}
|
||||
|
||||
const handleCheckboxChange = (categoryId: number) => {
|
||||
setSelectedCategories(
|
||||
(prev: any) =>
|
||||
setSelectedCategories((prev: any) =>
|
||||
prev.includes(categoryId)
|
||||
? prev.filter((id: any) => id !== categoryId) // Hapus jika sudah dipilih
|
||||
: [...prev, categoryId] // Tambahkan jika belum dipilih
|
||||
? prev.filter((id: any) => id !== categoryId)
|
||||
: [...prev, categoryId]
|
||||
);
|
||||
|
||||
// Perbarui filter kategori
|
||||
setCategoryFilter((prev) => {
|
||||
const updatedCategories = prev.split(",").filter(Boolean).map(Number);
|
||||
|
||||
|
|
@ -171,8 +170,8 @@ const BlogTable = () => {
|
|||
}
|
||||
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearch(e.target.value); // Perbarui state search
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
|
||||
setSearch(e.target.value);
|
||||
table.getColumn("judul")?.setFilterValue(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -181,7 +180,8 @@ const BlogTable = () => {
|
|||
<CardTitle>
|
||||
<div className="flex items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
{t("table", { defaultValue: "Table" })} {t("blog", { defaultValue: "Blog" })}
|
||||
{t("table", { defaultValue: "Table" })}{" "}
|
||||
{t("blog", { defaultValue: "Blog" })}
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/contributor/blog/create"}>
|
||||
|
|
@ -254,7 +254,9 @@ const BlogTable = () => {
|
|||
<div className="flex flex-row justify-between my-1 mx-1">
|
||||
<p>Filter</p>
|
||||
</div>
|
||||
<Label className="ml-2">{t("category", { defaultValue: "Category" })}</Label>
|
||||
<Label className="ml-2">
|
||||
{t("category", { defaultValue: "Category" })}
|
||||
</Label>
|
||||
{categories.length > 0 ? (
|
||||
categories.map((category) => (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -7,18 +7,34 @@ import { Icon } from "@iconify/react/dist/iconify.js";
|
|||
import NewContent from "@/components/landing-page/new-content";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { getCookiesDecrypt } from "@/lib/utils";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { checkWishlistStatus, deleteWishlist, getDetail, saveWishlist } from "@/service/landing/landing";
|
||||
import { close, error, loading, successCallback } from "@/config/swal";
|
||||
import {
|
||||
checkWishlistStatus,
|
||||
deleteWishlist,
|
||||
getDetail,
|
||||
getPublicSuggestionList,
|
||||
saveWishlist,
|
||||
} from "@/service/landing/landing";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { postActivityLog } from "@/service/content/content";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking";
|
||||
|
||||
const DetailInfo = () => {
|
||||
const [selectedSize, setSelectedSize] = useState<string>("L");
|
||||
const [selectedTab, setSelectedTab] = useState("video");
|
||||
const [emailShareList, setEmailShareList] = useState<any>();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const slug = String(params?.slug);
|
||||
const t = useTranslations("LandingPage");
|
||||
const [detailDataImage, setDetailDataImage] = useState<any>();
|
||||
const [selectedImage, setSelectedImage] = useState(0);
|
||||
const [isSaved, setIsSaved] = useState(false);
|
||||
|
|
@ -30,8 +46,14 @@ const DetailInfo = () => {
|
|||
const [main, setMain] = useState<any>();
|
||||
const [resolutionSelected, setResolutionSelected] = useState("720");
|
||||
const [imageSizeSelected, setImageSizeSelected] = useState("l");
|
||||
|
||||
const [emailShareInput, setEmailShareInput] = useState<any>();
|
||||
const [emailMessageInput, setEmailMessageInput] = useState();
|
||||
const [content, setContent] = useState<any>([]);
|
||||
const [listSuggestion, setListSuggestion] = useState<any>();
|
||||
const [width, setWidth] = useState<any>();
|
||||
const userRoleId = getCookiesDecrypt("urie");
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
let typeString = "image";
|
||||
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
|
|
@ -42,7 +64,12 @@ const DetailInfo = () => {
|
|||
const initFetch = async () => {
|
||||
const response = await getDetail(String(slug));
|
||||
console.log("detailImage", response);
|
||||
const responseGet = await getPublicSuggestionList(slug?.split("-")?.[0]);
|
||||
|
||||
setIsFromSPIT(response?.data?.data?.isFromSPIT);
|
||||
setWidth(window.innerWidth);
|
||||
setContent(response?.data.data);
|
||||
setListSuggestion(responseGet?.data?.data);
|
||||
setMain({
|
||||
id: response?.data?.data?.files[0]?.id,
|
||||
type: response?.data?.data?.fileType.name,
|
||||
|
|
@ -63,6 +90,42 @@ const DetailInfo = () => {
|
|||
setDetailDataImage(response?.data?.data);
|
||||
};
|
||||
|
||||
const handleEmailList = (e: any) => {
|
||||
const arrayEmail: any = [];
|
||||
for (let i = 0; i < emailShareList?.length; i += 1) {
|
||||
arrayEmail.push(emailShareList[i]);
|
||||
}
|
||||
if (e.which == 13) {
|
||||
if (e.target.value) {
|
||||
arrayEmail.push(e.target.value);
|
||||
setEmailShareList(arrayEmail);
|
||||
setEmailShareInput("");
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
async function shareToEmail() {
|
||||
if (Number(userRoleId) < 1 || userRoleId == undefined) {
|
||||
router.push("/auth/login");
|
||||
} else {
|
||||
const data = {
|
||||
mediaUploadId: slug?.split("-")?.[0],
|
||||
email: emailShareList || [emailShareInput],
|
||||
message: emailMessageInput,
|
||||
url: window.location.href,
|
||||
};
|
||||
loading();
|
||||
const res = await sendMediaUploadToEmail(data);
|
||||
if (res?.error) {
|
||||
error(res.message);
|
||||
return false;
|
||||
}
|
||||
close();
|
||||
successCallback("Konten Telah Dikirim");
|
||||
}
|
||||
}
|
||||
|
||||
const doBookmark = async () => {
|
||||
if (userId) {
|
||||
const data = {
|
||||
|
|
@ -114,6 +177,26 @@ const DetailInfo = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleShare = (type: any, url: any) => {
|
||||
if (Number(userRoleId) < 1 || userRoleId == undefined) {
|
||||
router.push("/auth/login");
|
||||
} else {
|
||||
sendActivityLog(2);
|
||||
sendActivityLog(4);
|
||||
if (type == "wa" && width <= 768) {
|
||||
window.open(`whatsapp://send?${url}`, "_blank");
|
||||
} else if (type == "wa" && width > 768) {
|
||||
window.open(
|
||||
`https://web.whatsapp.com/send?${url}`,
|
||||
"_blank",
|
||||
"noreferrer"
|
||||
);
|
||||
} else {
|
||||
window.open(url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sizes = [
|
||||
{ label: "XL", value: "3198 x 1798 px" },
|
||||
{ label: "L", value: "2399 x 1349 px" },
|
||||
|
|
@ -136,7 +219,7 @@ const DetailInfo = () => {
|
|||
const handleDownload = () => {
|
||||
if (downloadProgress === 0) {
|
||||
if (!userId) {
|
||||
router.push("/auth/login");
|
||||
router.push("/auth");
|
||||
} else {
|
||||
sendActivityLog(2);
|
||||
sendActivityLog(3);
|
||||
|
|
@ -196,7 +279,8 @@ const DetailInfo = () => {
|
|||
|
||||
xhr.addEventListener("readystatechange", () => {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
const contentType = xhr.getResponseHeader("content-type") || "application/octet-stream";
|
||||
const contentType =
|
||||
xhr.getResponseHeader("content-type") || "application/octet-stream";
|
||||
const extension = contentType.split("/")[1];
|
||||
const filename = `${name}.${extension}`;
|
||||
|
||||
|
|
@ -229,7 +313,11 @@ const DetailInfo = () => {
|
|||
<div className="md:w-3/4">
|
||||
{/* Gambar Besar */}
|
||||
<div className="relative">
|
||||
<img src={detailDataImage?.files[selectedImage]?.url} alt="Main" className="rounded-lg w-auto h-fit" />
|
||||
<img
|
||||
src={detailDataImage?.files[selectedImage]?.url}
|
||||
alt="Main"
|
||||
className="rounded-lg w-auto h-fit"
|
||||
/>
|
||||
<div className="absolute top-4 left-4"></div>
|
||||
</div>
|
||||
|
||||
|
|
@ -237,7 +325,10 @@ const DetailInfo = () => {
|
|||
<div className="py-4 flex flex-row gap-3">
|
||||
{detailDataImage?.files?.map((file: any, index: number) => (
|
||||
<a onClick={() => setSelectedImage(index)} key={file?.id}>
|
||||
<img src={file?.url} className="w-[120px] h-[90px] object-cover rounded-md cursor-pointer hover:ring-2 hover:ring-red-600" />
|
||||
<img
|
||||
src={file?.url}
|
||||
className="w-[120px] h-[90px] object-cover rounded-md cursor-pointer hover:ring-2 hover:ring-red-600"
|
||||
/>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -245,65 +336,109 @@ const DetailInfo = () => {
|
|||
{/* Footer Informasi */}
|
||||
<div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<div className="flex flex-row items-center mt-3 justify-between">
|
||||
oleh <span className="font-semibold text-black">{detailDataImage?.uploadedBy?.userLevel?.name}</span> | Diupdate pada {detailDataImage?.updatedAt} WIB |
|
||||
oleh
|
||||
<span className="font-semibold text-black">
|
||||
{detailDataImage?.uploadedBy?.userLevel?.name}
|
||||
</span>
|
||||
| Diupdate pada {detailDataImage?.updatedAt} WIB
|
||||
|
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
{detailDataImage?.clickCount}
|
||||
<p className="flex text-end">Kreator: {detailDataImage?.creatorName}</p>
|
||||
<p className="flex text-end">
|
||||
Kreator: {detailDataImage?.creatorName}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Keterangan */}
|
||||
<div className="w-full">
|
||||
<h1 className="flex flex-row font-bold text-2xl my-8">{detailDataImage?.title}</h1>
|
||||
<div className="font-light text-justify" dangerouslySetInnerHTML={{ __html: detailDataImage?.htmlDescription }} />
|
||||
<h1 className="flex flex-row font-bold text-2xl my-8">
|
||||
{detailDataImage?.title}
|
||||
</h1>
|
||||
<div
|
||||
className="font-light text-justify"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: detailDataImage?.htmlDescription,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bagian Kanan */}
|
||||
<div className="md:w-1/4 p-4 bg-[#f7f7f7] h-fit rounded-lg mx-4">
|
||||
<div className="p-4 bg-[#f7f7f7] dark:bg-slate-600 h-fit rounded-lg mx-4">
|
||||
{isSaved ? (
|
||||
<a onClick={() => handleDeleteWishlist()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
|
||||
<a
|
||||
onClick={() => handleDeleteWishlist()}
|
||||
className="flex flex-col mb-3 items-center justify-center cursor-pointer"
|
||||
>
|
||||
<Icon icon="material-symbols:bookmark" width={40} />
|
||||
<p className="text-base lg:text-lg">Hapus</p>
|
||||
<p className="text-base lg:text-lg">
|
||||
{t("delete", { defaultValue: "Delete" })}
|
||||
</p>
|
||||
</a>
|
||||
) : (
|
||||
<a onClick={() => doBookmark()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
|
||||
<Icon icon="material-symbols:bookmark-outline" width={40} />
|
||||
<p className="text-base lg:text-lg">Simpan</p>
|
||||
<a
|
||||
onClick={() => doBookmark()}
|
||||
className="flex flex-col mb-3 items-center justify-center cursor-pointer"
|
||||
>
|
||||
<Icon icon="material-symbols:bookmark-outline" width={25} />
|
||||
<p className="text-base lg:text-sm">
|
||||
{t("save", { defaultValue: "Save" })}
|
||||
</p>
|
||||
</a>
|
||||
)}
|
||||
|
||||
{/* garis */}
|
||||
<div className="border-t border-black my-4"></div>
|
||||
|
||||
<Link href={`/all/filter?title=polda&category=${detailDataImage?.category.id}`} className="bg-red-600 text-white text-xs font-bold px-3 py-3 my-3 flex justify-center items-center rounded">
|
||||
<div className="flex flex-col justify-center items-center gap-3">
|
||||
<div className="w-auto mb-3">
|
||||
<Link
|
||||
href={`/all/filter?title=polda&category=${detailDataImage?.category.id}`}
|
||||
className="bg-red-600 text-white text-xs font-bold px-3 py-3 my-3 rounded w-auto"
|
||||
>
|
||||
{detailDataImage?.category?.name}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center flex-wrap gap-2 mb-4">
|
||||
{detailDataImage?.tags?.split(",").map((tag: string) => (
|
||||
<a onClick={() => router.push(`/all/filter?tag=${tag}`)} key={tag} className="bg-gray-200 text-gray-700 text-xs px-3 py-1 rounded-full cursor-pointer hover:bg-gray-500">
|
||||
<a
|
||||
onClick={() => router.push(`/all/filter?tag=${tag}`)}
|
||||
key={tag}
|
||||
className="bg-gray-200 text-gray-700 text-xs px-3 py-3 font-semibold rounded-full cursor-pointer hover:bg-gray-500"
|
||||
>
|
||||
{tag}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-black my-4"></div>
|
||||
|
||||
{/* Opsi Ukuran Foto */}
|
||||
<h4 className="flex text-lg justify-center items-center font-semibold my-3">Opsi Ukuran Foto</h4>
|
||||
<h4 className="flex text-lg justify-center items-center font-semibold my-3">
|
||||
{t("imageSize", { defaultValue: "Image Size" })}
|
||||
</h4>
|
||||
<div className="border-t border-black my-4"></div>
|
||||
|
||||
<div className="space-y-2">
|
||||
{sizes.map((size: any) => (
|
||||
<div className="flex flex-row justify-between">
|
||||
<div key={size.label} className="items-center flex flex-row gap-2 cursor-pointer">
|
||||
<input type="radio" name="size" value={size.label} checked={selectedSize === size.label} onChange={() => setSelectedSize(size.label)} className="text-red-600 focus:ring-red-600" />
|
||||
<div className="text-sm">{size.label}</div>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="text-sm">{size.value}</div>
|
||||
<div
|
||||
key={size?.label}
|
||||
className="items-center flex flex-row gap-2 cursor-pointer"
|
||||
>
|
||||
<Input
|
||||
type="radio"
|
||||
name="size"
|
||||
value={size?.label}
|
||||
checked={selectedSize === size?.label}
|
||||
onChange={(e) => setImageSizeSelected(e.target.value)}
|
||||
className="text-red-600 focus:ring-red-600"
|
||||
/>
|
||||
<div className="text-sm">{size?.label}</div>
|
||||
</div>
|
||||
<div className="text-sm">{size?.value}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -311,18 +446,177 @@ const DetailInfo = () => {
|
|||
{/* Download Semua */}
|
||||
<div className="mt-4">
|
||||
<label className="flex items-center space-x-2 text-sm">
|
||||
<input type="checkbox" className="text-red-600 focus:ring-red-600" onChange={() => setIsDownloadAll(!isDownloadAll)} />
|
||||
<span>Download Semua File?</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="text-red-600 focus:ring-red-600"
|
||||
onChange={() => setIsDownloadAll(!isDownloadAll)}
|
||||
/>
|
||||
<span>
|
||||
{t("downloadAll", { defaultValue: "Download All" })}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Tombol Download */}
|
||||
<button onClick={handleDownload} className="mt-4 bg-red-600 text-white w-full py-2 flex justify-center items-center gap-1 rounded-md text-sm hover:bg-red-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||||
<path fill="white" d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z" />
|
||||
<button
|
||||
onClick={handleDownload}
|
||||
className="mt-4 bg-red-600 text-white w-full py-2 flex justify-center items-center gap-1 rounded-md text-sm hover:bg-red-700"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="white"
|
||||
d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z"
|
||||
/>
|
||||
</svg>
|
||||
Download
|
||||
{t("download", { defaultValue: "Download" })}
|
||||
</button>
|
||||
|
||||
{/* Tombol Bagikan */}
|
||||
<div className="flex flex-row mt-5 justify-center">
|
||||
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<button className="w-full flex items-center gap-2">
|
||||
{/* <Icon icon="oi:share" fontSize={20} /> */}
|
||||
<p className="text-base font-semibold mb-2">
|
||||
{t("share", { defaultValue: "Share" })}
|
||||
</p>
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="mb-2">
|
||||
{t("shareTo", { defaultValue: "Share To" })}
|
||||
</h1>
|
||||
<div className="flex flex-col mb-2">
|
||||
<p className="text-base font-semibold mb-1">
|
||||
{t("destinationEmail", {
|
||||
defaultValue: "Destination Email",
|
||||
})}
|
||||
</p>
|
||||
<Input
|
||||
value={emailShareInput}
|
||||
onChange={(event) =>
|
||||
setEmailShareInput(event.target.value)
|
||||
}
|
||||
onKeyPress={handleEmailList}
|
||||
type="email"
|
||||
placeholder={t("pressEnter", {
|
||||
defaultValue: "Press Enter",
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="bg-blue-500 text-white p-2 w-fit rounded-lg"
|
||||
onClick={() => shareToEmail()}
|
||||
>
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<a
|
||||
className="ml-8 cursor-pointer"
|
||||
onClick={() =>
|
||||
handleShare(
|
||||
"fb",
|
||||
`https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}"e=${content?.title}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon="brandico:facebook"
|
||||
height="20"
|
||||
className="px-auto text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
className="ml-5 cursor-pointer"
|
||||
onClick={() =>
|
||||
handleShare(
|
||||
"tw",
|
||||
`https://twitter.com/share?url=https%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}&text=${content?.title}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon="mdi:twitter"
|
||||
width="23"
|
||||
className="text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
className="ml-5 cursor-pointer"
|
||||
onClick={() =>
|
||||
handleShare(
|
||||
"wa",
|
||||
`text=${content?.title}%0D%0A%0D%0Ahttps%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon="ri:whatsapp-fill"
|
||||
width="23"
|
||||
className="text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
<Popover>
|
||||
<PopoverTrigger
|
||||
className="flex justify-end gap-1 cursor-pointer"
|
||||
asChild
|
||||
>
|
||||
<a
|
||||
className="ml-5 cursor-pointer"
|
||||
data-toggle="dropdown"
|
||||
href="#"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols-light:mail"
|
||||
width="23"
|
||||
className="text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="mb-2">
|
||||
{t("shareTo", { defaultValue: "Share To" })}
|
||||
</h1>
|
||||
<div className="flex flex-col mb-2">
|
||||
<p className="text-base font-semibold mb-1">
|
||||
{t("destinationEmail", {
|
||||
defaultValue: "Destination Email",
|
||||
})}
|
||||
</p>
|
||||
<Input
|
||||
value={emailShareInput}
|
||||
onChange={(event) =>
|
||||
setEmailShareInput(event.target.value)
|
||||
}
|
||||
onKeyPress={handleEmailList}
|
||||
type="email"
|
||||
placeholder={t("pressEnter", {
|
||||
defaultValue: "Press Enter",
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="bg-blue-500 text-white p-2 w-fit rounded-lg"
|
||||
onClick={() => shareToEmail()}
|
||||
>
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -332,13 +626,18 @@ const DetailInfo = () => {
|
|||
<div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-14">
|
||||
<p className="flex items-start text-lg">Berikan Komentar</p>
|
||||
<Textarea placeholder="Type your comments here." className="flex w-full" />
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-4 py-1">Kirim</button>
|
||||
<Textarea
|
||||
placeholder="Type your comments here."
|
||||
className="flex w-full"
|
||||
/>
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-4 py-1">
|
||||
Kirim
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konten Serupa */}
|
||||
<div className="">
|
||||
<div className="px-4 lg:px-24">
|
||||
<NewContent group="satker" type={"similar"} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,44 @@
|
|||
"use client";
|
||||
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { checkWishlistStatus, deleteWishlist, getDetail, saveWishlist } from "@/service/landing/landing";
|
||||
import {
|
||||
checkWishlistStatus,
|
||||
createPublicSuggestion,
|
||||
deletePublicSuggestion,
|
||||
deleteWishlist,
|
||||
getDetail,
|
||||
getPublicSuggestionList,
|
||||
saveWishlist,
|
||||
} from "@/service/landing/landing";
|
||||
import VideoPlayer from "@/utils/video-player";
|
||||
import NewContent from "@/components/landing-page/new-content";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { getCookiesDecrypt } from "@/lib/utils";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { close, error, loading, successCallback, warning } from "@/config/swal";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { postActivityLog } from "@/service/content/content";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking";
|
||||
import {
|
||||
checkMaliciousText,
|
||||
getPublicLocaleTimestamp,
|
||||
toBase64,
|
||||
} from "@/utils/globals";
|
||||
import Image from "next/image";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
import parse from "html-react-parser";
|
||||
|
||||
|
||||
const DetailVideo = () => {
|
||||
const [selectedSize, setSelectedSize] = useState<string>("L");
|
||||
|
|
@ -20,6 +47,7 @@ const DetailVideo = () => {
|
|||
const pathname = usePathname();
|
||||
const params = useParams();
|
||||
const slug = String(params?.slug);
|
||||
const searchParams = useSearchParams();
|
||||
const [detailDataVideo, setDetailDataVideo] = useState<any>();
|
||||
const [isSaved, setIsSaved] = useState(false);
|
||||
const [wishlistId, setWishlistId] = useState();
|
||||
|
|
@ -28,9 +56,21 @@ const DetailVideo = () => {
|
|||
const [downloadProgress, setDownloadProgress] = useState(0);
|
||||
const [isFromSPIT, setIsFromSPIT] = useState(false);
|
||||
const [main, setMain] = useState<any>();
|
||||
const [emailMessageInput, setEmailMessageInput] = useState();
|
||||
const [resolutionSelected, setResolutionSelected] = useState("720");
|
||||
|
||||
const t = useTranslations("LandingPage");
|
||||
const [emailShareInput, setEmailShareInput] = useState<any>();
|
||||
const [emailShareList, setEmailShareList] = useState<any>();
|
||||
const userRoleId = getCookiesDecrypt("urie");
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const id = searchParams?.get("id");
|
||||
const [width, setWidth] = useState<any>();
|
||||
const [content, setContent] = useState<any>([]);
|
||||
const [listSuggestion, setListSuggestion] = useState<any>();
|
||||
const [visibleInput, setVisibleInput] = useState(null);
|
||||
let typeString = "video";
|
||||
const MySwal = withReactContent(Swal);
|
||||
const [message, setMessage] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
|
|
@ -41,7 +81,12 @@ const DetailVideo = () => {
|
|||
const initFetch = async () => {
|
||||
const response = await getDetail(String(slug));
|
||||
console.log("detailVideo", response);
|
||||
const responseGet = await getPublicSuggestionList(slug?.split("-")?.[0]);
|
||||
|
||||
setIsFromSPIT(response?.data?.data?.isFromSPIT);
|
||||
setWidth(window.innerWidth);
|
||||
setContent(response?.data.data);
|
||||
setListSuggestion(responseGet?.data?.data);
|
||||
setMain({
|
||||
id: response?.data?.data?.files[0]?.id,
|
||||
type: response?.data?.data?.fileType.name,
|
||||
|
|
@ -62,6 +107,40 @@ const DetailVideo = () => {
|
|||
setDetailDataVideo(response?.data?.data);
|
||||
};
|
||||
|
||||
async function sendSuggestionParent() {
|
||||
if (message?.length > 3) {
|
||||
loading();
|
||||
const data = {
|
||||
mediaUploadId: slug?.split("-")?.[0],
|
||||
message,
|
||||
parentId: null,
|
||||
};
|
||||
|
||||
const response = await createPublicSuggestion(data);
|
||||
|
||||
console.log(response);
|
||||
setMessage("");
|
||||
|
||||
const responseGet = await getPublicSuggestionList(slug?.split("-")?.[0]);
|
||||
console.log(responseGet?.data?.data);
|
||||
setListSuggestion(responseGet?.data?.data);
|
||||
|
||||
// Hapus nilai semua input secara manual jika perlu
|
||||
const inputs = document.querySelectorAll("input");
|
||||
inputs.forEach((input) => {
|
||||
input.value = "";
|
||||
});
|
||||
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
const getInputValue = (e: any) => {
|
||||
const message = e.target.value;
|
||||
console.log(message);
|
||||
setMessage(message);
|
||||
};
|
||||
|
||||
const doBookmark = async () => {
|
||||
if (userId) {
|
||||
const data = {
|
||||
|
|
@ -83,6 +162,94 @@ const DetailVideo = () => {
|
|||
router.push("/auth");
|
||||
}
|
||||
};
|
||||
|
||||
async function sendSuggestionChild(parentId: any) {
|
||||
const inputElement = document.querySelector(
|
||||
`#input-comment-${parentId}`
|
||||
) as HTMLInputElement;
|
||||
|
||||
if (inputElement && inputElement.value.length > 3) {
|
||||
loading();
|
||||
const data = {
|
||||
mediaUploadId: slug?.split("-")?.[0],
|
||||
message: inputElement.value,
|
||||
parentId,
|
||||
};
|
||||
|
||||
console.log(data);
|
||||
const response = await createPublicSuggestion(data);
|
||||
console.log(response);
|
||||
const responseGet: any = await getPublicSuggestionList(
|
||||
slug?.split("-")?.[0]
|
||||
);
|
||||
console.log(responseGet?.data?.data);
|
||||
setListSuggestion(responseGet?.data?.data);
|
||||
|
||||
// Reset input field
|
||||
inputElement.value = "";
|
||||
|
||||
// document.querySelector("#comment-id-" + parentId)?.style.display = "none";
|
||||
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteDataSuggestion(dataId: any) {
|
||||
loading();
|
||||
const response = await deletePublicSuggestion(dataId);
|
||||
console.log(response);
|
||||
const responseGet = await getPublicSuggestionList(slug.split("-")?.[0]);
|
||||
console.log(responseGet?.data?.data);
|
||||
setListSuggestion(responseGet?.data?.data);
|
||||
close();
|
||||
}
|
||||
|
||||
const postDataChild = (id: any) => {
|
||||
const checkMessage = checkMaliciousText(message);
|
||||
if (checkMessage == "") {
|
||||
if (Number(userRoleId) < 1 || userRoleId == undefined) {
|
||||
router.push("/auth");
|
||||
} else {
|
||||
sendSuggestionChild(id);
|
||||
}
|
||||
} else {
|
||||
warning(checkMessage);
|
||||
}
|
||||
};
|
||||
|
||||
const handleShare = (type: any, url: any) => {
|
||||
if (Number(userRoleId) < 1 || userRoleId == undefined) {
|
||||
router.push("/auth/login");
|
||||
} else {
|
||||
sendActivityLog(2);
|
||||
sendActivityLog(4);
|
||||
if (type == "wa" && width <= 768) {
|
||||
window.open(`whatsapp://send?${url}`, "_blank");
|
||||
} else if (type == "wa" && width > 768) {
|
||||
window.open(
|
||||
`https://web.whatsapp.com/send?${url}`,
|
||||
"_blank",
|
||||
"noreferrer"
|
||||
);
|
||||
} else {
|
||||
window.open(url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const postData = () => {
|
||||
const checkMessage = checkMaliciousText(message);
|
||||
if (checkMessage == "") {
|
||||
if (Number(userRoleId) < 1 || userRoleId == undefined) {
|
||||
router.push("/auth");
|
||||
} else {
|
||||
sendSuggestionParent();
|
||||
}
|
||||
} else {
|
||||
warning(checkMessage);
|
||||
}
|
||||
};
|
||||
|
||||
async function checkWishlist() {
|
||||
if (userId) {
|
||||
const res = await checkWishlistStatus(slug.split("-")?.[0]);
|
||||
|
|
@ -177,6 +344,28 @@ const DetailVideo = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const deleteData = (dataId: any) => {
|
||||
MySwal.fire({
|
||||
title: "Delete Comment",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Delete",
|
||||
}).then((result: any) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteDataSuggestion(dataId);
|
||||
console.log(dataId);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const showInput = (e: any) => {
|
||||
console.log(document.querySelector(`#${e}`)?.classList);
|
||||
document.querySelector(`#${e}`)?.classList.toggle("none");
|
||||
setVisibleInput(visibleInput === e ? null : e);
|
||||
};
|
||||
|
||||
const downloadFile = (fileUrl: string, name: string) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
|
|
@ -192,7 +381,8 @@ const DetailVideo = () => {
|
|||
|
||||
xhr.addEventListener("readystatechange", () => {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
const contentType = xhr.getResponseHeader("content-type") || "application/octet-stream";
|
||||
const contentType =
|
||||
xhr.getResponseHeader("content-type") || "application/octet-stream";
|
||||
const extension = contentType.split("/")[1];
|
||||
const filename = `${name}.${extension}`;
|
||||
|
||||
|
|
@ -217,6 +407,61 @@ const DetailVideo = () => {
|
|||
xhr.send();
|
||||
};
|
||||
|
||||
async function shareToEmail() {
|
||||
if (Number(userRoleId) < 1 || userRoleId == undefined) {
|
||||
router.push("/auth/login");
|
||||
} else {
|
||||
const data = {
|
||||
mediaUploadId: id?.split("-")?.[0],
|
||||
email: emailShareList || [emailShareInput],
|
||||
message: emailMessageInput,
|
||||
url: window.location.href,
|
||||
};
|
||||
loading();
|
||||
const res = await sendMediaUploadToEmail(data);
|
||||
if (res?.error) {
|
||||
error(res.message);
|
||||
return false;
|
||||
}
|
||||
close();
|
||||
successCallback("Konten Telah Dikirim");
|
||||
}
|
||||
}
|
||||
|
||||
const handleEmailList = (e: any) => {
|
||||
const arrayEmail: any = [];
|
||||
for (let i = 0; i < emailShareList?.length; i += 1) {
|
||||
arrayEmail.push(emailShareList[i]);
|
||||
}
|
||||
if (e.which == 13) {
|
||||
if (e.target.value) {
|
||||
arrayEmail.push(e.target.value);
|
||||
setEmailShareList(arrayEmail);
|
||||
setEmailShareInput("");
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
function addDefaultProfile(ev: any) {
|
||||
ev.target.src = "/assets/avatar-profile.png";
|
||||
}
|
||||
|
||||
const shimmer = (w: number, h: number) => `
|
||||
<svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="g">
|
||||
<stop stop-color="#bcbcbd" offset="20%" />
|
||||
<stop stop-color="#f9fafb" offset="50%" />
|
||||
<stop stop-color="#bcbcbd" offset="70%" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="${w}" height="${h}" fill="#bcbcbd" />
|
||||
<rect id="r" width="${w}" height="${h}" fill="url(#g)" />
|
||||
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
|
||||
</svg>`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="px-4 md:px-24 py-4">
|
||||
|
|
@ -233,8 +478,11 @@ const DetailVideo = () => {
|
|||
<div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="flex flex-row items-center mt-3">
|
||||
oleh
|
||||
<span className="font-semibold text-black">{detailDataVideo?.uploadedBy?.userLevel?.name}</span>
|
||||
| Diupdate pada {detailDataVideo?.updatedAt} WIB |
|
||||
<span className="font-semibold text-black">
|
||||
{detailDataVideo?.uploadedBy?.userLevel?.name}
|
||||
</span>
|
||||
| Diupdate pada {detailDataVideo?.updatedAt}{" "}
|
||||
WIB |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
|
||||
{detailDataVideo?.clickCount}
|
||||
|
|
@ -244,7 +492,9 @@ const DetailVideo = () => {
|
|||
|
||||
{/* Keterangan */}
|
||||
<div className="w-full">
|
||||
<h1 className="flex flex-row font-bold text-2xl my-8">{detailDataVideo?.title}</h1>
|
||||
<h1 className="flex flex-row font-bold text-2xl my-8">
|
||||
{detailDataVideo?.title}
|
||||
</h1>
|
||||
<div
|
||||
className="font-light text-justify"
|
||||
dangerouslySetInnerHTML={{
|
||||
|
|
@ -255,29 +505,46 @@ const DetailVideo = () => {
|
|||
</div>
|
||||
|
||||
{/* Bagian Kanan */}
|
||||
<div className="md:w-1/4 p-4 bg-[#f7f7f7] rounded-lg mx-4 h-fit">
|
||||
<div className="md:w-1/4 p-4 bg-[#f7f7f7] dark:bg-slate-600 rounded-lg mx-4 h-fit">
|
||||
{isSaved ? (
|
||||
<a onClick={() => handleDeleteWishlist()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
|
||||
<a
|
||||
onClick={() => handleDeleteWishlist()}
|
||||
className="flex flex-col mb-3 items-center justify-center cursor-pointer"
|
||||
>
|
||||
<Icon icon="material-symbols:bookmark" width={40} />
|
||||
<p className="text-base lg:text-lg">Hapus</p>
|
||||
<p className="text-base lg:text-lg">
|
||||
{t("delete", { defaultValue: "Delete" })}
|
||||
</p>
|
||||
</a>
|
||||
) : (
|
||||
<a onClick={() => doBookmark()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
|
||||
<a
|
||||
onClick={() => doBookmark()}
|
||||
className="flex flex-col mb-3 items-center justify-center cursor-pointer"
|
||||
>
|
||||
<Icon icon="material-symbols:bookmark-outline" width={40} />
|
||||
<p className="text-base lg:text-lg">Simpan</p>
|
||||
<p className="text-base lg:text-lg">
|
||||
{t("save", { defaultValue: "Save" })}
|
||||
</p>
|
||||
</a>
|
||||
)}
|
||||
|
||||
{/* garis */}
|
||||
<div className="border-t border-black my-4"></div>
|
||||
|
||||
<Link href={`/all/filter?title=polda&category=${detailDataVideo?.category.id}`} className="bg-red-600 text-white text-xs font-bold px-3 py-3 my-3 flex justify-center items-center rounded">
|
||||
<Link
|
||||
href={`/all/filter?title=polda&category=${detailDataVideo?.category.id}`}
|
||||
className="bg-red-600 text-white text-xs font-bold px-3 py-3 my-3 flex justify-center items-center rounded"
|
||||
>
|
||||
{detailDataVideo?.categoryName}
|
||||
</Link>
|
||||
|
||||
<div className="flex justify-center flex-wrap gap-2 mb-4">
|
||||
{detailDataVideo?.tags.split(",").map((tag: string) => (
|
||||
<a onClick={() => router.push(`/all/filter?tag=${tag}`)} key={tag} className="bg-gray-200 text-gray-700 text-xs px-3 py-1 rounded-full cursor-pointer hover:bg-gray-500 hover:text-white">
|
||||
<a
|
||||
onClick={() => router.push(`/all/filter?tag=${tag}`)}
|
||||
key={tag}
|
||||
className="bg-gray-200 text-gray-700 text-xs px-3 py-1 rounded-full cursor-pointer hover:bg-gray-500 hover:text-white"
|
||||
>
|
||||
{tag}
|
||||
</a>
|
||||
))}
|
||||
|
|
@ -286,15 +553,27 @@ const DetailVideo = () => {
|
|||
<div className="border-t border-black my-4"></div>
|
||||
|
||||
{/* Opsi Ukuran Foto */}
|
||||
<h4 className="flex text-lg justify-center items-center font-semibold my-3">Opsi Ukuran Audio Visual</h4>
|
||||
<h4 className="flex text-lg justify-center items-center font-semibold my-3">
|
||||
{t("videoSize", { defaultValue: "Video Size" })}
|
||||
</h4>
|
||||
|
||||
<div className="border-t border-black my-4"></div>
|
||||
|
||||
<div className="space-y-2">
|
||||
{sizes.map((size: any) => (
|
||||
<div className="flex flex-row justify-between">
|
||||
<div key={size.label} className="items-center flex flex-row gap-2 cursor-pointer">
|
||||
<input type="radio" name="size" value={size.label} checked={selectedSize === size.label} onChange={() => setSelectedSize(size.label)} className="text-red-600 focus:ring-red-600" />
|
||||
<div
|
||||
key={size.label}
|
||||
className="items-center flex flex-row gap-2 cursor-pointer"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="size"
|
||||
value={size.label}
|
||||
checked={selectedSize === size.label}
|
||||
onChange={() => setSelectedSize(size.label)}
|
||||
className="text-red-600 focus:ring-red-600"
|
||||
/>
|
||||
<div className="text-sm">{size.label}</div>
|
||||
</div>
|
||||
<div className="">
|
||||
|
|
@ -307,33 +586,511 @@ const DetailVideo = () => {
|
|||
{/* Download Semua */}
|
||||
<div className="mt-4">
|
||||
<label className="flex items-center space-x-2 text-sm">
|
||||
<input type="checkbox" className="text-red-600 focus:ring-red-600" onChange={() => setIsDownloadAll(!isDownloadAll)} />
|
||||
<span>Download Semua File?</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="text-red-600 focus:ring-red-600"
|
||||
onChange={() => setIsDownloadAll(!isDownloadAll)}
|
||||
/>
|
||||
<span>
|
||||
{t("downloadAll", { defaultValue: "Download All" })}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Tombol Download */}
|
||||
<button onClick={handleDownload} className="mt-4 bg-red-600 text-white w-full py-2 flex justify-center items-center gap-1 rounded-md text-sm hover:bg-red-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||||
<path fill="white" d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z" />
|
||||
<button
|
||||
onClick={handleDownload}
|
||||
className="mt-4 bg-red-600 text-white w-full py-2 flex justify-center items-center gap-1 rounded-md text-sm hover:bg-red-700"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="white"
|
||||
d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z"
|
||||
/>
|
||||
</svg>
|
||||
Download
|
||||
{t("download", { defaultValue: "Download" })}
|
||||
</button>
|
||||
|
||||
{/* Tombol Bagikan */}
|
||||
<div className="flex flex-row justify-center py-3">
|
||||
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<button className="w-full flex items-center gap-2">
|
||||
{/* <Icon icon="oi:share" fontSize={20} /> */}
|
||||
<p className="text-base font-semibold mb-2">
|
||||
{t("share", { defaultValue: "Share" })}
|
||||
</p>
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="mb-2">
|
||||
{t("shareTo", { defaultValue: "Share To" })}
|
||||
</h1>
|
||||
<div className="flex flex-col mb-2">
|
||||
<p className="text-base font-semibold mb-1">
|
||||
{t("destinationEmail", {
|
||||
defaultValue: "Destination Email",
|
||||
})}
|
||||
</p>
|
||||
<Input
|
||||
value={emailShareInput}
|
||||
onChange={(event) =>
|
||||
setEmailShareInput(event.target.value)
|
||||
}
|
||||
onKeyPress={handleEmailList}
|
||||
type="email"
|
||||
placeholder={t("pressEnter", {
|
||||
defaultValue: "Press Enter",
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="bg-blue-500 text-white p-2 w-fit rounded-lg"
|
||||
onClick={() => shareToEmail()}
|
||||
>
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<a
|
||||
className="ml-8 cursor-pointer"
|
||||
onClick={() =>
|
||||
handleShare(
|
||||
"fb",
|
||||
`https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}"e=${content?.title}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon="brandico:facebook"
|
||||
height="20"
|
||||
className="px-auto text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
className="ml-5 cursor-pointer"
|
||||
onClick={() =>
|
||||
handleShare(
|
||||
"tw",
|
||||
`https://twitter.com/share?url=https%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}&text=${content?.title}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon="mdi:twitter"
|
||||
width="23"
|
||||
className="text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
className="ml-5 cursor-pointer"
|
||||
onClick={() =>
|
||||
handleShare(
|
||||
"wa",
|
||||
`text=${content?.title}%0D%0A%0D%0Ahttps%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon="ri:whatsapp-fill"
|
||||
width="23"
|
||||
className="text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
<Popover>
|
||||
<PopoverTrigger
|
||||
className="flex justify-end gap-1 cursor-pointer"
|
||||
asChild
|
||||
>
|
||||
<a
|
||||
className="ml-5 cursor-pointer"
|
||||
data-toggle="dropdown"
|
||||
href="#"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols-light:mail"
|
||||
width="23"
|
||||
className="text-red-600 text-center"
|
||||
/>
|
||||
</a>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="mb-2">
|
||||
{t("shareTo", { defaultValue: "Share To" })}
|
||||
</h1>
|
||||
<div className="flex flex-col mb-2">
|
||||
<p className="text-base font-semibold mb-1">
|
||||
{t("destinationEmail", {
|
||||
defaultValue: "Destination Email",
|
||||
})}
|
||||
</p>
|
||||
<Input
|
||||
value={emailShareInput}
|
||||
onChange={(event) =>
|
||||
setEmailShareInput(event.target.value)
|
||||
}
|
||||
onKeyPress={handleEmailList}
|
||||
type="email"
|
||||
placeholder={t("pressEnter", {
|
||||
defaultValue: "Press Enter",
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="bg-blue-500 text-white p-2 w-fit rounded-lg"
|
||||
onClick={() => shareToEmail()}
|
||||
>
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full mb-8">
|
||||
{/* Comment */}
|
||||
<div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
|
||||
<div className="flex flex-col my-16 p-4 lg:p-10 bg-[#f7f7f7] dark:bg-slate-600">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-14">
|
||||
<p className="flex items-start text-lg">Berikan Komentar</p>
|
||||
<Textarea placeholder="Type your comments here." className="flex w-full" />
|
||||
<button className="flex items-start bg-[#bb3523] text-white rounded-lg w-fit px-4 py-1">Kirim</button>
|
||||
<p className="flex items-start text-lg">
|
||||
{t("comment", { defaultValue: "Comment" })}
|
||||
</p>
|
||||
<Textarea
|
||||
placeholder="Type your comments here."
|
||||
className="flex w-full pb-12"
|
||||
onChange={getInputValue}
|
||||
/>
|
||||
<button
|
||||
onClick={() => postData()}
|
||||
className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-4 py-1"
|
||||
>
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="border-b-2 border-slate-300 mt-4 w-auto"></div>
|
||||
|
||||
<div>
|
||||
{listSuggestion?.map((data: any) => (
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-row mt-2 px-4 lg:px-14">
|
||||
<Image
|
||||
placeholder={`data:image/svg+xml;base64,${toBase64(
|
||||
shimmer(700, 475)
|
||||
)}`}
|
||||
width={1080}
|
||||
height={1080}
|
||||
src={data?.suggestionFrom?.profilePictureUrl}
|
||||
className="h-12 lg:h-16 w-12 lg:w-16 mr-2"
|
||||
onError={addDefaultProfile}
|
||||
alt=""
|
||||
/>
|
||||
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
|
||||
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
|
||||
{Number(data.suggestionFrom?.roleId) == 2 ||
|
||||
Number(data.suggestionFrom?.roleId) == 3 ||
|
||||
Number(data.suggestionFrom?.roleId) == 4
|
||||
? "HUMAS POLRI"
|
||||
: data.suggestionFrom?.fullname}
|
||||
{getPublicLocaleTimestamp(new Date(data.createdAt))}
|
||||
</p>
|
||||
<p className="text-slate-500 text-[13px] lg:text-sm mb-4">
|
||||
{data?.message}
|
||||
</p>
|
||||
<div>
|
||||
<a
|
||||
style={
|
||||
Number(data.suggestionFrom?.id) == Number(userId)
|
||||
? {
|
||||
display: "none",
|
||||
}
|
||||
: {}
|
||||
}
|
||||
onClick={() => showInput(`comment-id-${data.id}`)}
|
||||
className="mr-2"
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("reply", { defaultValue: "Reply" })}
|
||||
</small>
|
||||
</a>
|
||||
{Number(data.suggestionFrom?.id) == Number(userId) ||
|
||||
Number(userRoleId) == 2 ? (
|
||||
<a onClick={() => deleteData(data.id)}>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("delete", { defaultValue: "Delete" })}
|
||||
</small>
|
||||
</a>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{visibleInput === `comment-id-${data.id}` && (
|
||||
<div
|
||||
id={`comment-id-${data.id}`}
|
||||
className="px-4 pl-[72px] lg:px-14 lg:pl-32 mt-2 "
|
||||
>
|
||||
<Textarea
|
||||
id={`input-comment-${data.id}`}
|
||||
className="p-4 focus:outline-none focus:border-sky-500"
|
||||
placeholder={t("enterReply", {
|
||||
defaultValue: "Enter Reply",
|
||||
})}
|
||||
/>
|
||||
<div className="flex flex-row gap-3">
|
||||
<a onClick={() => postDataChild(data.id)}>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 mt-2 cursor-pointer">
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</small>
|
||||
</a>
|
||||
<a onClick={() => showInput(`comment-id-${data.id}`)}>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg mt-2 w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("cancel", { defaultValue: "Cancel" })}
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{data.children.length > 0
|
||||
? data.children?.map((child1: any) => (
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-16 lg:pl-32">
|
||||
<Image
|
||||
placeholder={`data:image/svg+xml;base64,${toBase64(
|
||||
shimmer(700, 475)
|
||||
)}`}
|
||||
width={1080}
|
||||
height={1080}
|
||||
src={child1.suggestionFrom?.profilePictureUrl}
|
||||
onError={addDefaultProfile}
|
||||
alt=""
|
||||
className="h-10 lg:h-16 w-10 lg:w-16 mr-2"
|
||||
/>
|
||||
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
|
||||
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
|
||||
{" "}
|
||||
<b>
|
||||
{Number(child1.suggestionFrom?.roleId) == 2 ||
|
||||
Number(child1.suggestionFrom?.roleId) == 3 ||
|
||||
Number(child1.suggestionFrom?.roleId) == 4
|
||||
? "HUMAS POLRI"
|
||||
: child1.suggestionFrom?.fullname}
|
||||
</b>{" "}
|
||||
{getPublicLocaleTimestamp(
|
||||
new Date(child1.createdAt)
|
||||
)}
|
||||
</p>
|
||||
<p className="text-slate-500 text-[13px] lg:text-sm mb-4">
|
||||
{parse(String(child1?.message))}
|
||||
</p>
|
||||
<div>
|
||||
<a
|
||||
style={
|
||||
Number(child1.suggestionFrom?.id) ==
|
||||
Number(userId)
|
||||
? {
|
||||
display: "none",
|
||||
}
|
||||
: {}
|
||||
}
|
||||
onClick={() =>
|
||||
showInput(`comment-id-${child1.id}`)
|
||||
}
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("reply", { defaultValue: "Reply" })}
|
||||
</small>
|
||||
</a>
|
||||
<a
|
||||
style={
|
||||
Number(child1.suggestionFrom?.id) ==
|
||||
Number(userId)
|
||||
? {}
|
||||
: {
|
||||
display: "none",
|
||||
}
|
||||
}
|
||||
onClick={() => deleteData(child1.id)}
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("delete", { defaultValue: "Delete" })}
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{visibleInput === `comment-id-${child1.id}` && (
|
||||
<div
|
||||
id={`comment-id-${child1.id}`}
|
||||
className="px-4 lg:px-14 pl-28 lg:pl-[200px]"
|
||||
>
|
||||
<Textarea
|
||||
name=""
|
||||
className="mt-2 "
|
||||
id={`input-comment-${child1.id}`}
|
||||
placeholder={t("enterReply", {
|
||||
defaultValue: "Enter Reply",
|
||||
})}
|
||||
/>
|
||||
<div className="flex flex-row mt-2 gap-3">
|
||||
<a onClick={() => postDataChild(child1.id)}>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</small>
|
||||
</a>
|
||||
<a
|
||||
onClick={() =>
|
||||
showInput(`comment-id-${child1.id}`)
|
||||
}
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("cancel", { defaultValue: "Cancel" })}
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{child1.children.length > 0
|
||||
? child1.children?.map((child2: any) => (
|
||||
<div className="">
|
||||
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-28 lg:pl-48">
|
||||
<Image
|
||||
placeholder={`data:image/svg+xml;base64,${toBase64(
|
||||
shimmer(700, 475)
|
||||
)}`}
|
||||
width={1080}
|
||||
height={1080}
|
||||
src={
|
||||
child2.suggestionFrom?.profilePictureUrl
|
||||
}
|
||||
className="h-9 lg:h-16 w-9 lg:w-16 mr-2"
|
||||
onError={addDefaultProfile}
|
||||
alt=""
|
||||
/>
|
||||
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
|
||||
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
|
||||
{" "}
|
||||
<b>
|
||||
{Number(
|
||||
child2.suggestionFrom?.roleId
|
||||
) == 2 ||
|
||||
Number(child2.suggestionFrom?.roleId) ==
|
||||
3 ||
|
||||
Number(child2.suggestionFrom?.roleId) ==
|
||||
4
|
||||
? "HUMAS POLRI"
|
||||
: child2.suggestionFrom?.fullname}
|
||||
</b>{" "}
|
||||
{getPublicLocaleTimestamp(
|
||||
new Date(child2.createdAt)
|
||||
)}
|
||||
</p>
|
||||
<p className="text-slate-500 text-sm mb-4">
|
||||
{parse(String(child2?.message))}
|
||||
</p>
|
||||
<div>
|
||||
<a
|
||||
style={
|
||||
Number(child2.suggestionFrom?.id) ==
|
||||
Number(userId)
|
||||
? {
|
||||
display: "none",
|
||||
}
|
||||
: {}
|
||||
}
|
||||
onClick={() =>
|
||||
showInput(`comment-id-${child2.id}`)
|
||||
}
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("reply", {
|
||||
defaultValue: "Reply",
|
||||
})}
|
||||
</small>
|
||||
</a>
|
||||
<a
|
||||
style={
|
||||
Number(child2.suggestionFrom?.id) ==
|
||||
Number(userId)
|
||||
? {}
|
||||
: {
|
||||
display: "none",
|
||||
}
|
||||
}
|
||||
onClick={() => deleteData(child2.id)}
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("delete", {
|
||||
defaultValue: "Delete",
|
||||
})}
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{visibleInput === `comment-id-${child2.id}` && (
|
||||
<div
|
||||
id={`comment-id-${child2.id}`}
|
||||
className="px-4 lg:px-14 pl-40 lg:pl-[265px]"
|
||||
>
|
||||
<Textarea
|
||||
name=""
|
||||
id={`input-comment-${child2.id}`}
|
||||
className="my-2"
|
||||
placeholder={t("enterReply", {
|
||||
defaultValue: "Enter Reply",
|
||||
})}
|
||||
/>
|
||||
<div className="flex flex-row gap-3">
|
||||
<a
|
||||
onClick={() => postDataChild(child2.id)}
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</small>
|
||||
</a>
|
||||
<a
|
||||
onClick={() =>
|
||||
showInput(`comment-id-${child2.id}`)
|
||||
}
|
||||
>
|
||||
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">
|
||||
{t("cancel", {
|
||||
defaultValue: "Cancel",
|
||||
})}
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
: ""}
|
||||
</div>
|
||||
))
|
||||
: ""}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konten Serupa */}
|
||||
<div className="">
|
||||
<div className="px-4 lg:px-24">
|
||||
<NewContent group="satker" type={"similar"} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ export default function FormCollaboration() {
|
|||
const router = useRouter();
|
||||
const editor = useRef(null);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const [taskOutput, setTaskOutput] = useState({
|
||||
all: false,
|
||||
|
|
@ -162,6 +163,18 @@ export default function FormCollaboration() {
|
|||
}
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
setIsSubmitting(true);
|
||||
|
||||
MySwal.fire({
|
||||
title: "Menyimpan...",
|
||||
text: "Mohon tunggu sebentar",
|
||||
allowOutsideClick: false,
|
||||
allowEscapeKey: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
},
|
||||
});
|
||||
|
||||
const requestData = {
|
||||
title: data.title,
|
||||
typeId: 11,
|
||||
|
|
@ -179,6 +192,8 @@ export default function FormCollaboration() {
|
|||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
Swal.close();
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
|
|
@ -188,6 +203,8 @@ export default function FormCollaboration() {
|
|||
}).then(() => {
|
||||
router.push("/in/supervisor/communications/collaboration");
|
||||
});
|
||||
|
||||
setIsSubmitting(false);
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import * as z from "zod";
|
|||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
|
||||
import {
|
||||
getCuratorUser,
|
||||
getTicketingPriority,
|
||||
|
|
@ -19,13 +17,6 @@ import {
|
|||
} from "@/service/communication/communication";
|
||||
import makeAnimated from "react-select/animated";
|
||||
import Select from "react-select";
|
||||
import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
} from "@radix-ui/react-select";
|
||||
import { SelectGroup } from "@/components/ui/select";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
const taskSchema = z.object({
|
||||
|
|
@ -45,39 +36,20 @@ interface Option {
|
|||
}
|
||||
|
||||
const CustomEditor = dynamic(
|
||||
() => {
|
||||
return import("@/components/editor/custom-editor");
|
||||
},
|
||||
() => import("@/components/editor/custom-editor"),
|
||||
{ ssr: false }
|
||||
);
|
||||
|
||||
export default function FormInternal() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const editor = useRef(null);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
|
||||
// State for various form fields
|
||||
const [taskOutput, setTaskOutput] = useState({
|
||||
all: false,
|
||||
video: false,
|
||||
audio: false,
|
||||
image: false,
|
||||
text: false,
|
||||
});
|
||||
|
||||
const [assignmentType, setAssignmentType] = useState("mediahub");
|
||||
const [assignmentCategory, setAssignmentCategory] = useState("publication");
|
||||
const [mainType, setMainType] = useState<number>(1); // untuk Tipe Penugasan
|
||||
const [type, setType] = useState<string>("1");
|
||||
const [options, setOptions] = useState<Option[]>([]);
|
||||
const [ticketPriority, setTicketPriority] = useState([]);
|
||||
const [selectedOption, setSelectedOption] = useState<Option | undefined>(
|
||||
undefined
|
||||
);
|
||||
const animatedComponent = makeAnimated();
|
||||
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState<Option | undefined>();
|
||||
const [selectedTarget, setSelectedTarget] = useState<number | null>(null);
|
||||
const animatedComponent = makeAnimated();
|
||||
const [isSubmitting, setIsSubmitting] = useState(false); // ⭐ NEW
|
||||
|
||||
const priority = [
|
||||
{ value: 1, label: "Low" },
|
||||
|
|
@ -93,54 +65,27 @@ export default function FormInternal() {
|
|||
resolver: zodResolver(taskSchema),
|
||||
});
|
||||
|
||||
const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const selectedValue = Number(event.target.value);
|
||||
setMainType(selectedValue);
|
||||
|
||||
setPlatformTypeVisible(selectedValue === 2);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getUser();
|
||||
getTicketPriority();
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleChange = (e: any) => {
|
||||
const selected = e;
|
||||
setSelectedOption(selected);
|
||||
setSelectedOption(e);
|
||||
};
|
||||
|
||||
const formatOptionLabel = (option: Option) => (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
{option.value} | {option.fullname}
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<b>{option.userLevel}</b>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
async function getTicketPriority() {
|
||||
const res = await getTicketingPriority();
|
||||
|
||||
if (res?.data !== null) {
|
||||
const rawData = res?.data?.data;
|
||||
setTicketPriority(rawData);
|
||||
// optional: setTicketPriority(rawData);
|
||||
}
|
||||
}
|
||||
|
||||
async function getUser() {
|
||||
const res = await getCuratorUser();
|
||||
|
||||
if (res?.data !== null) {
|
||||
const rawUser = res?.data?.data?.content;
|
||||
console.log("raw user", rawUser);
|
||||
|
||||
const optionArr: Option[] = rawUser.map((option: any) => ({
|
||||
id: option?.id,
|
||||
label: option?.username + option?.fullname + option?.userLevel?.name,
|
||||
|
|
@ -149,12 +94,23 @@ export default function FormInternal() {
|
|||
userLevel: option?.userLevel?.name,
|
||||
userLevelId: option?.userLevel?.id,
|
||||
}));
|
||||
|
||||
setOptions(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
setIsSubmitting(true); // ⭐ NEW
|
||||
MySwal.fire({
|
||||
title: "Menyimpan...",
|
||||
text: "Mohon tunggu, data sedang diproses.",
|
||||
allowOutsideClick: false,
|
||||
allowEscapeKey: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const requestData = {
|
||||
title: data.title,
|
||||
message: data.message,
|
||||
|
|
@ -167,6 +123,8 @@ export default function FormInternal() {
|
|||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
Swal.close(); // ⭐ Tutup loading
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
|
|
@ -176,6 +134,17 @@ export default function FormInternal() {
|
|||
}).then(() => {
|
||||
router.push("/in/shared/communication");
|
||||
});
|
||||
} catch (error) {
|
||||
Swal.close(); // Tutup loading jika error
|
||||
MySwal.fire({
|
||||
title: "Error",
|
||||
text: "Terjadi kesalahan saat menyimpan data.",
|
||||
icon: "error",
|
||||
});
|
||||
console.error("Error saat menyimpan data:", error);
|
||||
} finally {
|
||||
setIsSubmitting(false); // Reset state
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
|
|
@ -197,10 +166,8 @@ export default function FormInternal() {
|
|||
return (
|
||||
<Card>
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3"></p>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="flex flex-col justify-center items-center gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="w-6/12 space-y-2">
|
||||
<Label>
|
||||
Judul<span className="text-red-500">*</span>
|
||||
|
|
@ -222,8 +189,8 @@ export default function FormInternal() {
|
|||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-6/12">
|
||||
<div className="mt-5">
|
||||
<Label>
|
||||
Priority <span className="text-red-500">*</span>
|
||||
</Label>
|
||||
|
|
@ -234,17 +201,11 @@ export default function FormInternal() {
|
|||
setSelectedTarget(selectedOption?.value ?? null)
|
||||
}
|
||||
placeholder="Pilih"
|
||||
styles={{
|
||||
control: (base) => ({
|
||||
...base,
|
||||
minHeight: "40px",
|
||||
}),
|
||||
}}
|
||||
styles={{ control: (base) => ({ ...base, minHeight: "40px" }) }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-6/12">
|
||||
<div className="mt-5">
|
||||
<Label>Ditunjukan Untuk</Label>
|
||||
<Select
|
||||
options={options}
|
||||
|
|
@ -252,11 +213,10 @@ export default function FormInternal() {
|
|||
closeMenuOnSelect={false}
|
||||
components={animatedComponent}
|
||||
onChange={handleChange}
|
||||
formatOptionLabel={formatOptionLabel}
|
||||
isMulti={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-6/12 mt-5">
|
||||
<Label>Narasi Penugasan</Label>
|
||||
<Controller
|
||||
|
|
@ -270,12 +230,13 @@ export default function FormInternal() {
|
|||
<p className="text-red-400 text-sm">{errors.message.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-6/12 flex justify-end gap-3 mt-5">
|
||||
<Button type="button" color="primary" variant="outline">
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
<Button type="submit" color="primary" disabled={isSubmitting}>
|
||||
{isSubmitting ? "Menyimpan..." : "Submit"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -86,35 +86,29 @@ export default function FormAudio() {
|
|||
type AudioSchema = z.infer<typeof audioSchema>;
|
||||
const params = useParams();
|
||||
const locale = params?.locale;
|
||||
|
||||
const [selectedFileType, setSelectedFileType] = useState("original");
|
||||
|
||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||
const taskId = Cookies.get("taskId");
|
||||
const scheduleId = Cookies.get("scheduleId");
|
||||
const scheduleType = Cookies.get("scheduleType");
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const t = useTranslations("Form");
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
||||
const [tags, setTags] = useState<any[]>([]);
|
||||
const [thumbnail, setThumbnail] = useState<File | null>(null);
|
||||
const [preview, setPreview] = useState<string | null>(null);
|
||||
const [selectedLanguage, setSelectedLanguage] = useState("");
|
||||
|
||||
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||
useState("professional");
|
||||
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
|
||||
const [editorContent, setEditorContent] = useState("");
|
||||
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
||||
|
||||
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
||||
const [title, setTitle] = useState<string>("");
|
||||
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
||||
const [editingArticleId, setEditingArticleId] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState<boolean>(false);
|
||||
|
||||
const [articleIds, setArticleIds] = useState<string[]>([]);
|
||||
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
|
||||
const [articleBody, setArticleBody] = useState<string>("");
|
||||
|
|
@ -142,11 +136,12 @@ export default function FormAudio() {
|
|||
let uploadPersen = 0;
|
||||
const [isStartUpload, setIsStartUpload] = useState(false);
|
||||
const [counterProgress, setCounterProgress] = useState(0);
|
||||
|
||||
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
||||
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
||||
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
||||
const [fileError, setFileError] = useState<string | null>(null);
|
||||
type FileWithPreview = File & { preview: string };
|
||||
|
||||
const options: Option[] = [
|
||||
{ id: "all", label: "SEMUA" },
|
||||
|
|
@ -159,13 +154,34 @@ export default function FormAudio() {
|
|||
const audioRefs = useRef<HTMLAudioElement[]>([]);
|
||||
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
accept: {
|
||||
"audio/mpeg": [".mp3"],
|
||||
"audio/wav": [".wav"],
|
||||
},
|
||||
maxSize: 100 * 1024 * 1024,
|
||||
multiple: true,
|
||||
accept: { "audio/*": [] },
|
||||
onDrop: (acceptedFiles) => {
|
||||
onDrop: (acceptedFiles, fileRejections) => {
|
||||
setFileError(null);
|
||||
|
||||
if (fileRejections.length > 0) {
|
||||
const messages = fileRejections
|
||||
.map((rej) => rej.errors.map((e) => e.message).join(", "))
|
||||
.join(", ");
|
||||
setFileError(messages || "File tidak valid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (acceptedFiles.length === 0) {
|
||||
setFileError("Wajib upload minimal 1 file mp3 atau wav");
|
||||
return;
|
||||
}
|
||||
|
||||
const filesWithPreview = acceptedFiles.map((file) =>
|
||||
Object.assign(file, { preview: URL.createObjectURL(file) })
|
||||
);
|
||||
setFiles((prev) => [...prev, ...filesWithPreview]);
|
||||
setFiles(filesWithPreview);
|
||||
|
||||
setValue("files", filesWithPreview, { shouldValidate: true });
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -184,8 +200,13 @@ export default function FormAudio() {
|
|||
descriptionOri: z.string().optional(),
|
||||
rewriteDescription: z.string().optional(),
|
||||
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
||||
|
||||
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
category: z.string().min(1, { message: "Category diperlukan" }),
|
||||
files: z
|
||||
.array(z.any())
|
||||
.min(1, { message: "Wajib upload minimal 1 file mp3 atau wav" }),
|
||||
tags: z
|
||||
.array(z.string().min(1))
|
||||
.min(1, { message: "Wajib isi minimal 1 tag" }),
|
||||
});
|
||||
|
||||
const {
|
||||
|
|
@ -200,6 +221,8 @@ export default function FormAudio() {
|
|||
description: "",
|
||||
descriptionOri: "",
|
||||
rewriteDescription: "",
|
||||
category: "",
|
||||
tags: [],
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -398,20 +421,18 @@ export default function FormAudio() {
|
|||
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter" && e.currentTarget.value.trim()) {
|
||||
e.preventDefault();
|
||||
const newTag = e.currentTarget.value.trim();
|
||||
if (!tags.includes(newTag)) {
|
||||
setTags((prevTags) => [...prevTags, newTag]); // Add new tag
|
||||
if (inputRef.current) {
|
||||
inputRef.current.value = ""; // Clear input field
|
||||
}
|
||||
}
|
||||
const newTags = [...tags, e.currentTarget.value.trim()];
|
||||
setTags(newTags);
|
||||
setValue("tags", newTags, { shouldValidate: true });
|
||||
e.currentTarget.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveTag = (index: number) => {
|
||||
setTags((prevTags) => prevTags.filter((_, i) => i !== index)); // Remove tag
|
||||
const newTags = tags.filter((_, i) => i !== index);
|
||||
setTags(newTags);
|
||||
setValue("tags", newTags, { shouldValidate: true });
|
||||
};
|
||||
|
||||
const handleRemoveImage = (index: number) => {
|
||||
setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index));
|
||||
};
|
||||
|
|
@ -441,7 +462,7 @@ export default function FormAudio() {
|
|||
|
||||
if (findCategory) {
|
||||
// setValue("categoryId", findCategory.id);
|
||||
setSelectedCategory(findCategory.id); // Set the selected category
|
||||
setSelectedCategory(findCategory.id);
|
||||
const response = await getTagsBySubCategoryId(findCategory.id);
|
||||
setTags(response?.data?.data);
|
||||
}
|
||||
|
|
@ -514,7 +535,7 @@ export default function FormAudio() {
|
|||
tags: string;
|
||||
isYoutube: boolean;
|
||||
isInternationalMedia: boolean;
|
||||
attachFromScheduleId?: number; // ✅ Tambahkan properti ini
|
||||
attachFromScheduleId?: number;
|
||||
} = {
|
||||
...data,
|
||||
title: finalTitle,
|
||||
|
|
@ -535,7 +556,7 @@ export default function FormAudio() {
|
|||
let id = Cookies.get("idCreate");
|
||||
|
||||
if (scheduleId !== undefined) {
|
||||
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||
requestData.attachFromScheduleId = Number(scheduleId);
|
||||
}
|
||||
|
||||
if (id == undefined) {
|
||||
|
|
@ -844,9 +865,16 @@ export default function FormAudio() {
|
|||
<div className="flex items-center">
|
||||
<div className="py-3 w-full space-y-2">
|
||||
<Label>{t("category", { defaultValue: "Category" })}</Label>
|
||||
<Controller
|
||||
name="category"
|
||||
control={control}
|
||||
rules={{ required: "Category is required" }}
|
||||
render={({ field, fieldState }) => (
|
||||
<>
|
||||
<Select
|
||||
value={selectedCategory}
|
||||
value={field.value}
|
||||
onValueChange={(id) => {
|
||||
field.onChange(id);
|
||||
console.log("Selected Category ID:", id);
|
||||
setSelectedCategory(id);
|
||||
}}
|
||||
|
|
@ -865,6 +893,14 @@ export default function FormAudio() {
|
|||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{fieldState.error && (
|
||||
<p className="text-sm text-red-500">
|
||||
{fieldState.error.message}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-3 py-2">
|
||||
|
|
@ -1234,7 +1270,14 @@ export default function FormAudio() {
|
|||
<Label>
|
||||
{t("select-file", { defaultValue: "Select File" })}
|
||||
</Label>
|
||||
<Fragment>
|
||||
<Controller
|
||||
name="files"
|
||||
control={control}
|
||||
rules={{
|
||||
required: "Wajib upload minimal 1 file mp3 atau wav",
|
||||
}}
|
||||
render={({ field, fieldState }) => (
|
||||
<>
|
||||
<div {...getRootProps({ className: "dropzone" })}>
|
||||
<input {...getInputProps({ multiple: true })} />
|
||||
<div className="w-full text-center border-dashed border border-default-200 dark:border-default-300 rounded-md py-[52px] flex items-center flex-col">
|
||||
|
|
@ -1250,8 +1293,19 @@ export default function FormAudio() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* pesan error dari validasi dropzone */}
|
||||
{fileError && (
|
||||
<p className="text-sm text-red-500 mt-1">{fileError}</p>
|
||||
)}
|
||||
|
||||
{/* pesan error dari schema */}
|
||||
{fieldState.error && (
|
||||
<p className="text-sm text-red-500 mt-1">
|
||||
{fieldState.error.message}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{files.length ? (
|
||||
<Fragment>
|
||||
<div className="space-y-4 mt-4">
|
||||
{files.map((file, idx) => (
|
||||
<div
|
||||
|
|
@ -1263,10 +1317,7 @@ export default function FormAudio() {
|
|||
</p>
|
||||
<audio
|
||||
controls
|
||||
src={file.preview ?? URL.createObjectURL(file)}
|
||||
ref={(el) => {
|
||||
if (el) audioRefs.current[idx] = el;
|
||||
}}
|
||||
src={file.preview}
|
||||
onPlay={() => handlePlay(idx)}
|
||||
className="w-full rounded"
|
||||
>
|
||||
|
|
@ -1275,17 +1326,25 @@ export default function FormAudio() {
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{files.length > 0 && (
|
||||
<div className="flex justify-between gap-2 mt-3">
|
||||
<Button
|
||||
color="destructive"
|
||||
onClick={handleRemoveAllFiles}
|
||||
onClick={() => {
|
||||
setFiles([]);
|
||||
setFileError(null);
|
||||
setValue("files", [], { shouldValidate: true });
|
||||
}}
|
||||
>
|
||||
{t("remove-all", { defaultValue: "Remove All" })}
|
||||
</Button>
|
||||
</div>
|
||||
</Fragment>
|
||||
) : null}
|
||||
</Fragment>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1327,6 +1386,7 @@ export default function FormAudio() {
|
|||
onKeyDown={handleAddTag}
|
||||
ref={inputRef}
|
||||
/>
|
||||
|
||||
<div className="mt-3">
|
||||
{tags.map((tag, index) => (
|
||||
<span
|
||||
|
|
@ -1344,7 +1404,14 @@ export default function FormAudio() {
|
|||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{errors.tags && (
|
||||
<p className="text-sm text-red-500 mt-1">
|
||||
{errors.tags.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="px-3 py-3">
|
||||
<div className="flex flex-col gap-3 space-y-2">
|
||||
<Label>
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ export default function FormVideoDetail() {
|
|||
format: details?.files[0]?.format,
|
||||
});
|
||||
|
||||
if (details.publishedForObject) {
|
||||
if (details?.publishedForObject) {
|
||||
const publisherIds = details.publishedForObject.map(
|
||||
(obj: any) => obj.id
|
||||
);
|
||||
|
|
@ -453,7 +453,7 @@ export default function FormVideoDetail() {
|
|||
<div className="py-3 w-full space-y-2">
|
||||
<Label>{t("category", { defaultValue: "Category" })}</Label>
|
||||
<Select
|
||||
value={detail?.category.name} // Nilai default berdasarkan detail
|
||||
value={detail?.category.name}
|
||||
onValueChange={(id) => {
|
||||
console.log("Selected Category:", id);
|
||||
setSelectedTarget(id);
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ export default function FormVideo() {
|
|||
const scheduleType = Cookies.get("scheduleType");
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
const [selectedFileType, setSelectedFileType] = useState("original");
|
||||
|
||||
const t = useTranslations("Form");
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
||||
|
|
@ -100,19 +99,16 @@ export default function FormVideo() {
|
|||
const [thumbnail, setThumbnail] = useState<File | null>(null);
|
||||
const [preview, setPreview] = useState<string | null>(null);
|
||||
const [selectedLanguage, setSelectedLanguage] = useState("");
|
||||
|
||||
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||
useState("professional");
|
||||
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
|
||||
const [editorContent, setEditorContent] = useState("");
|
||||
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
||||
|
||||
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
||||
const [title, setTitle] = useState<string>("");
|
||||
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
||||
const [editingArticleId, setEditingArticleId] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState<boolean>(false);
|
||||
|
||||
const [articleIds, setArticleIds] = useState<string[]>([]);
|
||||
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
|
||||
const [articleBody, setArticleBody] = useState<string>("");
|
||||
|
|
@ -126,11 +122,9 @@ export default function FormVideo() {
|
|||
const [articleImages, setArticleImages] = useState<string[]>([]);
|
||||
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [fileError, setFileError] = useState<string | null>(null);
|
||||
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||
|
||||
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
||||
|
||||
const [selectedTarget, setSelectedTarget] = useState("");
|
||||
const [unitSelection, setUnitSelection] = useState({
|
||||
allUnit: false,
|
||||
|
|
@ -165,21 +159,33 @@ export default function FormVideo() {
|
|||
"video/mp4": [".mp4"],
|
||||
"video/quicktime": [".mov"],
|
||||
},
|
||||
maxSize: MAX_FILE_SIZE,
|
||||
onDrop: (acceptedFiles: File[]) => {
|
||||
const filteredFiles = acceptedFiles.filter(
|
||||
(file) =>
|
||||
ACCEPTED_FILE_TYPES.includes(file.type) && file.size <= MAX_FILE_SIZE
|
||||
maxSize: 500 * 1024 * 1024,
|
||||
multiple: true,
|
||||
onDrop: (acceptedFiles, fileRejections) => {
|
||||
setFileError(null);
|
||||
|
||||
if (fileRejections.length > 0) {
|
||||
const messages = fileRejections
|
||||
.map((rej) => rej.errors.map((e) => e.message).join(", "))
|
||||
.join(", ");
|
||||
setFileError(messages || "File tidak valid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (acceptedFiles.length === 0) {
|
||||
setFileError("Wajib upload minimal 1 file video");
|
||||
return;
|
||||
}
|
||||
|
||||
const filesWithPreview = acceptedFiles.map((file) =>
|
||||
Object.assign(file, { preview: URL.createObjectURL(file) })
|
||||
);
|
||||
|
||||
const filesWithPreview = filteredFiles.map((file) =>
|
||||
Object.assign(file, {
|
||||
preview: URL.createObjectURL(file),
|
||||
})
|
||||
);
|
||||
|
||||
setFiles(filesWithPreview);
|
||||
setValue("files", filesWithPreview);
|
||||
setFiles((prev) => {
|
||||
const updatedFiles = [...prev, ...filesWithPreview];
|
||||
setValue("files", updatedFiles, { shouldValidate: true });
|
||||
return updatedFiles;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -668,9 +668,27 @@ export default function FormContestDetail() {
|
|||
<Checkbox
|
||||
id={key}
|
||||
checked={taskOutput[key as keyof typeof taskOutput]}
|
||||
onCheckedChange={(value) =>
|
||||
setTaskOutput({ ...taskOutput, [key]: value })
|
||||
onCheckedChange={(value) => {
|
||||
if (key === "all") {
|
||||
const newValue = Boolean(value);
|
||||
setTaskOutput({
|
||||
all: newValue,
|
||||
video: newValue,
|
||||
audio: newValue,
|
||||
image: newValue,
|
||||
text: newValue,
|
||||
});
|
||||
} else {
|
||||
setTaskOutput((prev) => {
|
||||
const updated = { ...prev, [key]: Boolean(value) };
|
||||
// Update 'all' jika semua sub-checkbox true
|
||||
const allChecked = Object.entries(updated)
|
||||
.filter(([k]) => k !== "all")
|
||||
.every(([_, v]) => v);
|
||||
return { ...updated, all: allChecked };
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
|
|
@ -687,9 +705,27 @@ export default function FormContestDetail() {
|
|||
<Checkbox
|
||||
id={key}
|
||||
checked={unitSelection[key as keyof typeof unitSelection]}
|
||||
onCheckedChange={(value) =>
|
||||
setUnitSelection({ ...unitSelection, [key]: value })
|
||||
onCheckedChange={(value) => {
|
||||
if (key === "allUnit") {
|
||||
const newValue = Boolean(value);
|
||||
setUnitSelection({
|
||||
allUnit: newValue,
|
||||
mabes: newValue,
|
||||
polda: newValue,
|
||||
polres: newValue,
|
||||
satker: newValue,
|
||||
});
|
||||
} else {
|
||||
setUnitSelection((prev) => {
|
||||
const updated = { ...prev, [key]: Boolean(value) };
|
||||
// Update 'allUnit' jika semua sub-checkbox true
|
||||
const allChecked = Object.entries(updated)
|
||||
.filter(([k]) => k !== "allUnit")
|
||||
.every(([_, v]) => v);
|
||||
return { ...updated, allUnit: allChecked };
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor={key}>
|
||||
{key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import {
|
|||
} from "@/components/ui/select";
|
||||
import { toast } from "sonner";
|
||||
import { close, loading } from "@/config/swal";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul harus diisi" }),
|
||||
|
|
@ -59,6 +60,7 @@ export default function FormLiveReport() {
|
|||
const [endTime, setEndTime] = useState("09:00");
|
||||
const [scheduleTypeId, setScheduleTypeId] = React.useState<string>("1");
|
||||
const [youtubeUrl, setYoutubeUrl] = useState("");
|
||||
const t = useTranslations("Form");
|
||||
|
||||
const [date, setDate] = React.useState<DateRange | undefined>({
|
||||
from: new Date(),
|
||||
|
|
@ -233,7 +235,7 @@ export default function FormLiveReport() {
|
|||
</div>
|
||||
<div className="flex flex-col lg:flex-row mb-4 mt-2 items-start lg:items-center justify-between">
|
||||
<div className="flex flex-col space-y-2">
|
||||
<Label className="mr-3 mb-1">Tanggal</Label>
|
||||
<Label className="mr-3 mb-1">{t("date")}</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild className="px-0">
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -254,6 +254,9 @@ export default function FormTask() {
|
|||
};
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
try {
|
||||
loading();
|
||||
|
||||
const fileTypeMapping = {
|
||||
all: "1",
|
||||
video: "2",
|
||||
|
|
@ -261,7 +264,6 @@ export default function FormTask() {
|
|||
image: "3",
|
||||
text: "5",
|
||||
};
|
||||
|
||||
const unitMapping = {
|
||||
allUnit: "0",
|
||||
mabes: "1",
|
||||
|
|
@ -273,35 +275,18 @@ export default function FormTask() {
|
|||
.filter((key) => unitSelection[key as keyof typeof unitSelection])
|
||||
.map((key) => unitMapping[key as keyof typeof unitMapping])
|
||||
.join(",");
|
||||
|
||||
const selectedOutputs = Object.keys(taskOutput)
|
||||
.filter((key) => taskOutput[key as keyof typeof taskOutput])
|
||||
.map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping])
|
||||
.join(",");
|
||||
|
||||
const requestData: {
|
||||
id?: number;
|
||||
title: string;
|
||||
assignedToLevel: any;
|
||||
assignmentPurpose: any;
|
||||
assignmentTypeId: string;
|
||||
fileTypeOutput: string;
|
||||
narration: string;
|
||||
platformType: string | null;
|
||||
assignmentMainTypeId: any;
|
||||
taskType: string;
|
||||
assignedToRole: string;
|
||||
broadcastType: string;
|
||||
attachmentUrl: string[];
|
||||
} = {
|
||||
const requestData = {
|
||||
...data,
|
||||
// assignmentType,
|
||||
// assignmentCategory,
|
||||
assignedToLevel: handlePoldaPolresChange(),
|
||||
assignmentPurpose: assignmentPurposeString,
|
||||
assignedToRole: selectedTarget,
|
||||
taskType: taskType,
|
||||
broadcastType: broadcastType,
|
||||
taskType,
|
||||
broadcastType,
|
||||
assignmentMainTypeId: mainType,
|
||||
assignmentTypeId: type,
|
||||
fileTypeOutput: selectedOutputs,
|
||||
|
|
@ -312,50 +297,41 @@ export default function FormTask() {
|
|||
};
|
||||
|
||||
const response = await createTask(requestData);
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
const id = response?.data?.data.id;
|
||||
loading();
|
||||
if (imageFiles?.length == 0) {
|
||||
setIsImageUploadFinish(true);
|
||||
} else {
|
||||
imageFiles?.map(async (item: any, index: number) => {
|
||||
await uploadResumableFile(index, String(id), item, "1", "0");
|
||||
});
|
||||
}
|
||||
|
||||
if (videoFiles?.length == 0) {
|
||||
setIsVideoUploadFinish(true);
|
||||
} else {
|
||||
videoFiles?.map(async (item: any, index: number) => {
|
||||
await uploadResumableFile(index, String(id), item, "2", "0");
|
||||
});
|
||||
}
|
||||
|
||||
if (textFiles?.length == 0) {
|
||||
setIsTextUploadFinish(true);
|
||||
} else {
|
||||
textFiles?.map(async (item: any, index: number) => {
|
||||
await uploadResumableFile(index, String(id), item, "3", "0");
|
||||
});
|
||||
}
|
||||
|
||||
if (audioFiles?.length == 0) {
|
||||
setIsAudioUploadFinish(true);
|
||||
} else {
|
||||
audioFiles.map(async (item: FileWithPreview, index: number) => {
|
||||
await uploadResumableFile(
|
||||
index,
|
||||
String(id),
|
||||
item, // Use .file to access the actual File object
|
||||
"4",
|
||||
"0" // Optional: Replace with actual duration if available
|
||||
if (imageFiles?.length === 0) setIsImageUploadFinish(true);
|
||||
else
|
||||
imageFiles.map(
|
||||
async (item, idx) =>
|
||||
await uploadResumableFile(idx, String(id), item, "1", "0")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (videoFiles?.length === 0) setIsVideoUploadFinish(true);
|
||||
else
|
||||
videoFiles.map(
|
||||
async (item, idx) =>
|
||||
await uploadResumableFile(idx, String(id), item, "2", "0")
|
||||
);
|
||||
|
||||
if (textFiles?.length === 0) setIsTextUploadFinish(true);
|
||||
else
|
||||
textFiles.map(
|
||||
async (item, idx) =>
|
||||
await uploadResumableFile(idx, String(id), item, "3", "0")
|
||||
);
|
||||
|
||||
if (audioFiles?.length === 0) setIsAudioUploadFinish(true);
|
||||
else
|
||||
audioFiles.map(
|
||||
async (item, idx) =>
|
||||
await uploadResumableFile(idx, String(id), item, "4", "0")
|
||||
);
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error saat kirim data:", err);
|
||||
close();
|
||||
error("Terjadi kesalahan saat mengirim data.");
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
|
|
@ -403,7 +379,7 @@ export default function FormTask() {
|
|||
|
||||
const handleStopRecording = () => {
|
||||
setIsRecording(false);
|
||||
setTimer(120); // Reset the timer to 2 minutes for the next recording
|
||||
setTimer(120);
|
||||
};
|
||||
|
||||
const addAudioElement = (blob: Blob) => {
|
||||
|
|
@ -413,13 +389,11 @@ export default function FormTask() {
|
|||
audio.controls = true;
|
||||
document.body.appendChild(audio);
|
||||
|
||||
// Convert Blob to File and add preview
|
||||
const fileWithPreview: FileWithPreview = Object.assign(
|
||||
new File([blob], "voiceNote.webm", { type: "audio/webm" }),
|
||||
{ preview: url }
|
||||
);
|
||||
|
||||
// Add to state
|
||||
setAudioFile(fileWithPreview);
|
||||
setAudioFiles((prev) => [...prev, fileWithPreview]);
|
||||
};
|
||||
|
|
@ -542,7 +516,6 @@ export default function FormTask() {
|
|||
setLinks([...links, ""]);
|
||||
};
|
||||
|
||||
// Remove a specific link row
|
||||
const handleRemoveRow = (index: number) => {
|
||||
const updatedLinks = links.filter((_: any, i: any) => i !== index);
|
||||
setLinks(updatedLinks);
|
||||
|
|
@ -551,7 +524,9 @@ export default function FormTask() {
|
|||
return (
|
||||
<Card>
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-lg font-semibold mb-3">{t("form-task", { defaultValue: "Form Task" })}</p>
|
||||
<p className="text-lg font-semibold mb-3">
|
||||
{t("form-task", { defaultValue: "Form Task" })}
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="gap-5 mb-5">
|
||||
|
|
@ -577,7 +552,11 @@ export default function FormTask() {
|
|||
</div>
|
||||
<div className="flex flex-col sm:flex-row lg:flex-row sm:items-center lg:items-center">
|
||||
<div className="mt-5 space-y-2">
|
||||
<Label>{t("assignment-selection", { defaultValue: "Assignment Selection" })}</Label>
|
||||
<Label>
|
||||
{t("assignment-selection", {
|
||||
defaultValue: "Assignment Selection",
|
||||
})}
|
||||
</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Choose" />
|
||||
|
|
@ -706,7 +685,9 @@ export default function FormTask() {
|
|||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-5 space-y-2">
|
||||
<Label>{t("assigment-type", { defaultValue: "Assigment Type" })} </Label>
|
||||
<Label>
|
||||
{t("assigment-type", { defaultValue: "Assigment Type" })}{" "}
|
||||
</Label>
|
||||
<RadioGroup
|
||||
value={taskType}
|
||||
onValueChange={(value) => setTaskType(String(value))}
|
||||
|
|
@ -720,7 +701,9 @@ export default function FormTask() {
|
|||
</div>
|
||||
{/* RadioGroup Assignment Category */}
|
||||
<div className="mt-5 space-y-2">
|
||||
<Label>{t("type-of-task", { defaultValue: "Type Of Task" })}</Label>
|
||||
<Label>
|
||||
{t("type-of-task", { defaultValue: "Type Of Task" })}
|
||||
</Label>
|
||||
<RadioGroup
|
||||
value={type} // State yang dipetakan ke value RadioGroup
|
||||
onValueChange={(value) => setType(value)} // Mengubah nilai state ketika pilihan berubah
|
||||
|
|
@ -799,10 +782,14 @@ export default function FormTask() {
|
|||
)}
|
||||
</div>
|
||||
<div className="space-y-2.5 mt-5">
|
||||
<Label htmlFor="attachments">{t("attachment", { defaultValue: "Attachment" })}</Label>
|
||||
<Label htmlFor="attachments">
|
||||
{t("attachment", { defaultValue: "Attachment" })}
|
||||
</Label>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<Label>{t("audio-visual", { defaultValue: "Audio Visual" })}</Label>
|
||||
<Label>
|
||||
{t("audio-visual", { defaultValue: "Audio Visual" })}
|
||||
</Label>
|
||||
<FileUploader
|
||||
accept={{
|
||||
"video/*": [],
|
||||
|
|
@ -876,7 +863,9 @@ export default function FormTask() {
|
|||
{isRecording && <p>Recording... {timer} seconds remaining</p>}{" "}
|
||||
{/* Display remaining time */}
|
||||
<div className="mt-4 space-y-2">
|
||||
<Label className="">{t("news-links", { defaultValue: "News Links" })}</Label>
|
||||
<Label className="">
|
||||
{t("news-links", { defaultValue: "News Links" })}
|
||||
</Label>
|
||||
{links.map((link, index) => (
|
||||
<div key={index} className="flex items-center gap-2 mt-2">
|
||||
<Input
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import search from "@/app/[locale]/(protected)/app/chat/components/search";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useParams } from "next/navigation";
|
||||
import router from "next/router";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import search from "@/app/[locale]/(protected)/app/chat/components/search";
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ const DetailAudio = () => {
|
|||
const handleDownload = () => {
|
||||
if (downloadProgress === 0) {
|
||||
if (!userId) {
|
||||
router.push("/auth/login");
|
||||
router.push("/auth");
|
||||
} else {
|
||||
sendActivityLog(2);
|
||||
sendActivityLog(3);
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ const DetailDocument = () => {
|
|||
const handleDownload = () => {
|
||||
if (downloadProgress === 0) {
|
||||
if (!userId) {
|
||||
router.push("/auth/login");
|
||||
router.push("/auth");
|
||||
} else {
|
||||
sendActivityLog(2);
|
||||
sendActivityLog(3);
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ const DetailImage = (data: any) => {
|
|||
const handleDownload = () => {
|
||||
if (downloadProgress === 0) {
|
||||
if (!userId) {
|
||||
router.push("/auth/login");
|
||||
router.push("/auth");
|
||||
} else {
|
||||
sendActivityLog(2);
|
||||
sendActivityLog(3);
|
||||
|
|
@ -676,7 +676,7 @@ const DetailImage = (data: any) => {
|
|||
key={size?.label}
|
||||
className="items-center flex flex-row gap-2 cursor-pointer"
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
type="radio"
|
||||
name="size"
|
||||
value={size?.label}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ const DetailVideo = () => {
|
|||
const handleDownload = () => {
|
||||
if (downloadProgress === 0) {
|
||||
if (!userId) {
|
||||
router.push("/auth/login");
|
||||
router.push("/auth");
|
||||
} else {
|
||||
sendActivityLog(2);
|
||||
sendActivityLog(3);
|
||||
|
|
@ -404,7 +404,6 @@ const DetailVideo = () => {
|
|||
console.log(responseGet?.data?.data);
|
||||
setListSuggestion(responseGet?.data?.data);
|
||||
|
||||
// Hapus nilai semua input secara manual jika perlu
|
||||
const inputs = document.querySelectorAll("input");
|
||||
inputs.forEach((input) => {
|
||||
input.value = "";
|
||||
|
|
@ -465,7 +464,6 @@ const DetailVideo = () => {
|
|||
return (
|
||||
<>
|
||||
<div className="px-4 md:px-24 py-4">
|
||||
{/* Container Utama */}
|
||||
<div className="rounded-md overflow-hidden md:flex">
|
||||
{/* Bagian Kiri */}
|
||||
<div className="md:w-3/4">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import React, { Component } from "react";
|
||||
import Places from "./Maps"; // Pastikan ini adalah komponen Places
|
||||
|
||||
import Places from "./Maps";
|
||||
interface MapHomeProps {
|
||||
newLat?: any;
|
||||
newLng?: any;
|
||||
draggable?: boolean;
|
||||
setLocation: (location: string) => void; // Pastikan properti ini ada
|
||||
setLocation: (location: string) => void;
|
||||
}
|
||||
|
||||
class MapHome extends Component<MapHomeProps> {
|
||||
|
|
@ -20,7 +19,7 @@ class MapHome extends Component<MapHomeProps> {
|
|||
<Places
|
||||
center={{ lat: Number(lat), lng: Number(lng) }}
|
||||
draggable={draggable}
|
||||
onLocationChange={setLocation} // Kirimkan setLocation ke Places
|
||||
onLocationChange={setLocation}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Geocode.setApiKey(GoogleMapsAPI);
|
|||
export default function Places(props: {
|
||||
center: { lat: number; lng: number };
|
||||
draggable?: boolean;
|
||||
onLocationChange?: (location: string) => void; // Tambahkan onLocationChange
|
||||
onLocationChange?: (location: string) => void;
|
||||
}) {
|
||||
const { isLoaded } = useLoadScript({
|
||||
googleMapsApiKey: GoogleMapsAPI,
|
||||
|
|
@ -31,7 +31,7 @@ export default function Places(props: {
|
|||
lat={center.lat}
|
||||
lng={center.lng}
|
||||
draggable={draggable}
|
||||
onLocationChange={onLocationChange} // Kirimkan properti onLocationChange
|
||||
onLocationChange={onLocationChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ interface MapProps {
|
|||
lat: number;
|
||||
lng: number;
|
||||
draggable?: boolean;
|
||||
onLocationChange?: (location: string) => void; // Tambahkan properti ini
|
||||
onLocationChange?: (location: string) => void;
|
||||
}
|
||||
|
||||
function Map(props: MapProps) {
|
||||
|
|
@ -73,7 +73,7 @@ function Map(props: MapProps) {
|
|||
console.log(lat, lng);
|
||||
getAddressFromLatLong(lat, lng);
|
||||
if (onLocationChange) {
|
||||
onLocationChange(`Latitude: ${lat}, Longitude: ${lng}`); // Kirimkan lokasi ke parent melalui onLocationChange
|
||||
onLocationChange(`Latitude: ${lat}, Longitude: ${lng}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ function Map(props: MapProps) {
|
|||
Cookies.set("map_long", `${lng}`, { expires: 1 });
|
||||
console.log("Address:", address);
|
||||
if (onLocationChange) {
|
||||
onLocationChange(address); // Kirimkan alamat jika berhasil
|
||||
onLocationChange(address);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export const GoogleMapsAPI = "AIzaSyCOkxoeKykE60L_nM4VS1JYJqBmqy2GA0Q";
|
||||
export const GoogleMapsAPI = "AIzaSyCuQHorDceMCzlSgrB9AEY5ns8KeriFsME";
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@
|
|||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
|
|
@ -1987,6 +1988,7 @@
|
|||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"string-width": "^5.1.2",
|
||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
||||
|
|
@ -2003,6 +2005,7 @@
|
|||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -2014,6 +2017,7 @@
|
|||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
|
|
@ -2633,166 +2637,6 @@
|
|||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/core-downloads-tracker": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.2.0.tgz",
|
||||
"integrity": "sha512-d49s7kEgI5iX40xb2YPazANvo7Bx0BLg/MNRwv+7BVpZUzXj1DaVCKlQTDex3gy/0jsCb4w7AY2uH4t4AJvSog==",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/material": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.2.0.tgz",
|
||||
"integrity": "sha512-NTuyFNen5Z2QY+I242MDZzXnFIVIR6ERxo7vntFi9K1wCgSwvIl0HcAO2OOydKqqKApE6omRiYhpny1ZhGuH7Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6",
|
||||
"@mui/core-downloads-tracker": "^7.2.0",
|
||||
"@mui/system": "^7.2.0",
|
||||
"@mui/types": "^7.4.4",
|
||||
"@mui/utils": "^7.2.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@types/react-transition-group": "^4.4.12",
|
||||
"clsx": "^2.1.1",
|
||||
"csstype": "^3.1.3",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^19.1.0",
|
||||
"react-transition-group": "^4.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.5.0",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@mui/material-pigment-css": "^7.2.0",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/styled": {
|
||||
"optional": true
|
||||
},
|
||||
"@mui/material-pigment-css": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/private-theming": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.2.0.tgz",
|
||||
"integrity": "sha512-y6N1Yt3T5RMxVFnCh6+zeSWBuQdNDm5/UlM0EAYZzZR/1u+XKJWYQmbpx4e+F+1EpkYi3Nk8KhPiQDi83M3zIw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6",
|
||||
"@mui/utils": "^7.2.0",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/styled-engine": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.2.0.tgz",
|
||||
"integrity": "sha512-yq08xynbrNYcB1nBcW9Fn8/h/iniM3ewRguGJXPIAbHvxEF7Pz95kbEEOAAhwzxMX4okhzvHmk0DFuC5ayvgIQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6",
|
||||
"@emotion/cache": "^11.14.0",
|
||||
"@emotion/serialize": "^1.3.3",
|
||||
"@emotion/sheet": "^1.4.0",
|
||||
"csstype": "^3.1.3",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.4.1",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/styled": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/system": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.2.0.tgz",
|
||||
"integrity": "sha512-PG7cm/WluU6RAs+gNND2R9vDwNh+ERWxPkqTaiXQJGIFAyJ+VxhyKfzpdZNk0z0XdmBxxi9KhFOpgxjehf/O0A==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6",
|
||||
"@mui/private-theming": "^7.2.0",
|
||||
"@mui/styled-engine": "^7.2.0",
|
||||
"@mui/types": "^7.4.4",
|
||||
"@mui/utils": "^7.2.0",
|
||||
"clsx": "^2.1.1",
|
||||
"csstype": "^3.1.3",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.5.0",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/styled": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/types": {
|
||||
"version": "7.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.4.tgz",
|
||||
|
|
@ -3381,6 +3225,7 @@
|
|||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
|
@ -5017,78 +4862,6 @@
|
|||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
||||
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@types/aria-query": "^5.0.1",
|
||||
"aria-query": "5.3.0",
|
||||
"chalk": "^4.1.0",
|
||||
"dom-accessibility-api": "^0.5.9",
|
||||
"lz-string": "^1.5.0",
|
||||
"pretty-format": "^27.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom/node_modules/ansi-styles": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom/node_modules/aria-query": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom/node_modules/dom-accessibility-api": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@testing-library/dom/node_modules/pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ansi-styles": "^5.0.0",
|
||||
"react-is": "^17.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom/node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@testing-library/jest-dom": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz",
|
||||
|
|
@ -5266,13 +5039,6 @@
|
|||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/aria-query": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
|
|
@ -6312,12 +6078,14 @@
|
|||
"node_modules/any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
|
|
@ -6330,6 +6098,7 @@
|
|||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
|
|
@ -6373,7 +6142,8 @@
|
|||
"node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
|
|
@ -6824,6 +6594,7 @@
|
|||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
|
|
@ -7045,6 +6816,7 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -7172,6 +6944,7 @@
|
|||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
|
|
@ -7195,6 +6968,7 @@
|
|||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
|
|
@ -7716,6 +7490,7 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"cssesc": "bin/cssesc"
|
||||
},
|
||||
|
|
@ -8507,7 +8282,8 @@
|
|||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "5.2.0",
|
||||
|
|
@ -8532,7 +8308,8 @@
|
|||
"node_modules/dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
|
|
@ -8681,7 +8458,8 @@
|
|||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
|
|
@ -8743,16 +8521,11 @@
|
|||
"url": "https://github.com/sindresorhus/emittery?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-mart": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-5.6.0.tgz",
|
||||
"integrity": "sha512-eJp3QRe79pjwa+duv+n7+5YsNhRcMl812EcFVwrnRvYKoNPoQb5qxU8DG6Bgwji0akHdp6D4Ln6tYLG58MFSow==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -9980,6 +9753,7 @@
|
|||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.6",
|
||||
"signal-exit": "^4.0.1"
|
||||
|
|
@ -10076,6 +9850,7 @@
|
|||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
|
@ -10286,6 +10061,7 @@
|
|||
"version": "10.3.10",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
|
||||
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^2.3.5",
|
||||
|
|
@ -10307,6 +10083,7 @@
|
|||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
|
|
@ -10318,6 +10095,7 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
|
|
@ -10326,6 +10104,7 @@
|
|||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
|
|
@ -11512,6 +11291,7 @@
|
|||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
|
|
@ -12111,6 +11891,7 @@
|
|||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
|
||||
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
|
|
@ -12785,6 +12566,7 @@
|
|||
"version": "1.21.7",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
|
|
@ -13331,7 +13113,8 @@
|
|||
"node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
"version": "0.390.0",
|
||||
|
|
@ -13341,16 +13124,6 @@
|
|||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lz-string": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"lz-string": "bin/bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
|
||||
|
|
@ -14982,6 +14755,7 @@
|
|||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
|
|
@ -15095,6 +14869,7 @@
|
|||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0",
|
||||
"object-assign": "^4.0.1",
|
||||
|
|
@ -15435,6 +15210,7 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -15493,6 +15269,7 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -15998,6 +15775,7 @@
|
|||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
|
@ -16060,6 +15838,7 @@
|
|||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -16068,6 +15847,7 @@
|
|||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
|
||||
"integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -16184,6 +15964,7 @@
|
|||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
||||
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"camelcase-css": "^2.0.1"
|
||||
},
|
||||
|
|
@ -16202,6 +15983,7 @@
|
|||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
|
||||
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
|
@ -16236,6 +16018,7 @@
|
|||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
|
|
@ -16247,6 +16030,7 @@
|
|||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
|
||||
"integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
|
|
@ -16258,6 +16042,7 @@
|
|||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
||||
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
|
@ -16282,6 +16067,7 @@
|
|||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
|
|
@ -16293,7 +16079,8 @@
|
|||
"node_modules/postcss-value-parser": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/preact": {
|
||||
"version": "10.12.1",
|
||||
|
|
@ -17030,6 +16817,7 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"pify": "^2.3.0"
|
||||
}
|
||||
|
|
@ -17051,6 +16839,7 @@
|
|||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
|
|
@ -17062,6 +16851,7 @@
|
|||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
|
|
@ -18440,6 +18230,7 @@
|
|||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"eastasianwidth": "^0.2.0",
|
||||
"emoji-regex": "^9.2.2",
|
||||
|
|
@ -18457,6 +18248,7 @@
|
|||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
|
|
@ -18469,12 +18261,14 @@
|
|||
"node_modules/string-width-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/string-width/node_modules/ansi-regex": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -18486,6 +18280,7 @@
|
|||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
|
|
@ -18657,6 +18452,7 @@
|
|||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
|
|
@ -18783,6 +18579,7 @@
|
|||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"commander": "^4.0.0",
|
||||
|
|
@ -18804,6 +18601,7 @@
|
|||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -18919,6 +18717,7 @@
|
|||
"version": "3.4.17",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
|
||||
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
|
|
@ -18963,6 +18762,7 @@
|
|||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
|
|
@ -18974,6 +18774,7 @@
|
|||
"version": "15.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.0.0",
|
||||
"read-cache": "^1.0.0",
|
||||
|
|
@ -19040,6 +18841,7 @@
|
|||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0"
|
||||
}
|
||||
|
|
@ -19048,6 +18850,7 @@
|
|||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
||||
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"thenify": ">= 3.1.0 < 4"
|
||||
},
|
||||
|
|
@ -19297,7 +19100,8 @@
|
|||
"node_modules/ts-interface-checker": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
|
||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-morph": {
|
||||
"version": "18.0.0",
|
||||
|
|
@ -19507,7 +19311,7 @@
|
|||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
@ -20396,6 +20200,7 @@
|
|||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.1.0",
|
||||
"string-width": "^5.0.1",
|
||||
|
|
@ -20413,6 +20218,7 @@
|
|||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
|
|
@ -20428,12 +20234,14 @@
|
|||
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
|
|
@ -20447,6 +20255,7 @@
|
|||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -20458,6 +20267,7 @@
|
|||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -20469,6 +20279,7 @@
|
|||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue