feat:add kostum form contest, fix status table contest,add content rewrite 3 id,generate article

This commit is contained in:
Anang Yusman 2025-01-06 22:06:02 +08:00
parent 0fdfa4b8ba
commit 65ec901d9a
15 changed files with 554 additions and 233 deletions

View File

@ -108,12 +108,8 @@ const columns: ColumnDef<any>[] = [
diterima: "bg-green-100 text-green-600",
"menunggu review": "bg-orange-100 text-orange-600",
};
// Mengambil `statusName` dari data API
const status = row.getValue("statusName") as string;
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
// Gunakan `statusName` untuk pencocokan
const statusName = status?.toLocaleLowerCase();
const statusStyles =
statusColors[statusName] || "bg-gray-100 text-gray-600";
@ -124,7 +120,7 @@ const columns: ColumnDef<any>[] = [
statusStyles
)}
>
{status} {/* Tetap tampilkan nilai asli */}
{status}
</Badge>
);
},

View File

@ -66,7 +66,7 @@ const columns: ColumnDef<any>[] = [
return (
<div>
{isActive ? (
<b className="text-info">Terkirim</b>
<b className="text-blue-500">Terkirim</b>
) : (
<b className="text-danger">Belum Terkirim</b>
)}

View File

@ -66,7 +66,7 @@ const columns: ColumnDef<any>[] = [
return (
<div>
{isActive ? (
<b className="text-info">Terkirim</b>
<b className="text-blue-500">Terkirim</b>
) : (
<b className="text-danger">Belum Terkirim</b>
)}

View File

@ -84,10 +84,17 @@ const columns: ColumnDef<any>[] = [
accessorKey: "isPublishForAll",
header: "Status",
cell: ({ row }) => {
const isPublishForAll = row.getValue("isPublishForAll");
return (
<span className="whitespace-nowrap text-blue-600">
{row.getValue("isPublishForAll")}
</span>
<Badge
className={`whitespace-nowrap px-2 py-1 rounded-full ${
isPublishForAll
? "bg-green-100 text-green-600" // Warna hijau untuk status "Publish"
: "bg-orange-100 text-orange-600" // Warna kuning untuk status "Pending"
}`}
>
{isPublishForAll ? "Publish" : "Pending"}
</Badge>
);
},
},

View File

@ -54,6 +54,7 @@ import { loading } from "@/config/swal";
import { getCookiesDecrypt } from "@/lib/utils";
import { Icon } from "@iconify/react/dist/iconify.js";
import { error } from "@/lib/swal";
import dynamic from "next/dynamic";
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -96,6 +97,13 @@ type Detail = {
uploadedById: number;
};
const ViewEditor = dynamic(
() => {
return import("@/components/editor/view-editor");
},
{ ssr: false }
);
export default function FormAudioDetail() {
const MySwal = withReactContent(Swal);
const router = useRouter();
@ -180,7 +188,7 @@ export default function FormAudioDetail() {
const getCategories = async () => {
try {
const category = await listEnableCategory(fileTypeId);
const resCategory: Category[] = category.data.data.content;
const resCategory: Category[] = category?.data.data.content;
setCategories(resCategory);
console.log("data category", resCategory);
@ -206,7 +214,7 @@ export default function FormAudioDetail() {
async function initState() {
if (id) {
const response = await detailMedia(id);
const details = response.data?.data;
const details = response?.data?.data;
console.log("detail", details);
setFiles(details?.files);
setDetail(details);
@ -400,12 +408,7 @@ export default function FormAudioDetail() {
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={detail?.description}
onChange={onChange}
className="dark:text-black"
/>
<ViewEditor initialData={detail?.htmlDescription} />
)}
/>
{errors.description?.message && (

View File

@ -51,6 +51,7 @@ import { CloudUpload } from "lucide-react";
import Image from "next/image";
import { error, loading } from "@/config/swal";
import { Item } from "@radix-ui/react-dropdown-menu";
import dynamic from "next/dynamic";
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -70,6 +71,13 @@ type Category = {
name: string;
};
const CustomEditor = dynamic(
() => {
return import("@/components/editor/custom-editor");
},
{ ssr: false }
);
export default function FormAudio() {
const MySwal = withReactContent(Swal);
const router = useRouter();
@ -281,19 +289,47 @@ export default function FormAudio() {
};
const handleArticleIdClick = async (id: string) => {
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
setIsLoading(true); // Tampilkan loading segera setelah ID diklik
try {
// Panggil API untuk mendapatkan data artikel
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
const articleImagesData = articleData?.imagesUrl?.split(",");
// Bersihkan konten articleBody dari elemen gambar
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
// Pisahkan URL gambar menjadi array
const articleImagesData = articleData?.imagesUrl?.split(",");
// Tunggu hingga `articleBody` tidak null atau kosong
const waitForGeneratedBody = async () => {
return new Promise<void>((resolve) => {
const interval = setInterval(() => {
if (cleanArticleBody) {
clearInterval(interval); // Hentikan polling jika articleBody tersedia
resolve();
}
}, 500); // Periksa setiap 500ms
});
};
// Tunggu hingga articleBody selesai di-generate
await waitForGeneratedBody();
// Set data artikel ke state setelah validasi
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
} catch (error) {
console.error("Error fetching article details:", error);
} finally {
// Hilangkan loading setelah semua data selesai di-generate
setIsLoading(false);
}
};
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
@ -861,14 +897,18 @@ export default function FormAudio() {
<Controller
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={articleBody || value}
onChange={onChange}
className="dark:text-black"
/>
)}
render={({ field: { onChange, value } }) =>
isLoading ? (
<div className="flex justify-center items-center h-40">
<p className="text-gray-500">Loading...</p>
</div>
) : (
<CustomEditor
onChange={onChange}
initialData={articleBody || value}
/>
)
}
/>
{errors.description?.message && (
<p className="text-red-400 text-sm">

View File

@ -295,7 +295,7 @@ export default function FormImage() {
setIsGeneratedArticle(true);
setArticleIds((prevIds: string[]) => {
if (prevIds.length < 5) {
if (prevIds.length < 3) {
return [...prevIds, newArticleId];
} else {
const updatedIds = [...prevIds];
@ -308,19 +308,47 @@ export default function FormImage() {
};
const handleArticleIdClick = async (id: string) => {
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
setIsLoading(true); // Tampilkan loading segera setelah ID diklik
try {
// Panggil API untuk mendapatkan data artikel
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
const articleImagesData = articleData?.imagesUrl?.split(",");
// Bersihkan konten articleBody dari elemen gambar
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
// Pisahkan URL gambar menjadi array
const articleImagesData = articleData?.imagesUrl?.split(",");
// Tunggu hingga `articleBody` tidak null atau kosong
const waitForGeneratedBody = async () => {
return new Promise<void>((resolve) => {
const interval = setInterval(() => {
if (cleanArticleBody) {
clearInterval(interval); // Hentikan polling jika articleBody tersedia
resolve();
}
}, 500); // Periksa setiap 500ms
});
};
// Tunggu hingga articleBody selesai di-generate
await waitForGeneratedBody();
// Set data artikel ke state setelah validasi
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
} catch (error) {
console.error("Error fetching article details:", error);
} finally {
// Hilangkan loading setelah semua data selesai di-generate
setIsLoading(false);
}
};
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
@ -862,7 +890,7 @@ export default function FormImage() {
</div>
{isGeneratedArticle && (
<div className="mt-3 pb-0 flex flex-row ">
<div className="mt-3 pb-0 flex flex-row">
{articleIds.map((id: string, index: number) => (
<p
key={index}
@ -915,24 +943,18 @@ export default function FormImage() {
<Controller
control={control}
name="description"
render={({ field: { onChange, value } }) => (
// <JoditEditor
// ref={editor}
// value={articleBody || value}
// onChange={onChange}
// className="dark:text-black"
// />
<<<<<<< HEAD
<CustomEditor
onChange={onChange}
// value={articleBody || value}
=======
<CustomEditor
onChange={onChange}
initialData={articleBody || value}
>>>>>>> e2193a8c9ac305726ea8f34d9b99e36b010f6841
/>
)}
render={({ field: { onChange, value } }) =>
isLoading ? (
<div className="flex justify-center items-center h-40">
<p className="text-gray-500">Loading...</p>
</div>
) : (
<CustomEditor
onChange={onChange}
initialData={articleBody || value}
/>
)
}
/>
{errors.description?.message && (
<p className="text-red-400 text-sm">

View File

@ -330,11 +330,11 @@ export default function FormConvertSPIT() {
setIsGeneratedArticle(true);
setArticleIds((prevIds: string[]) => {
if (prevIds.length < 5) {
if (prevIds.length < 3) {
return [...prevIds, newArticleId];
} else {
const updatedIds = [...prevIds];
updatedIds[4] = newArticleId;
updatedIds[2] = newArticleId;
return updatedIds;
}
});

View File

@ -54,6 +54,7 @@ import { loading } from "@/config/swal";
import { getCookiesDecrypt } from "@/lib/utils";
import { Icon } from "@iconify/react/dist/iconify.js";
import { error } from "@/lib/swal";
import dynamic from "next/dynamic";
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -96,6 +97,13 @@ type Detail = {
uploadedById: number;
};
const ViewEditor = dynamic(
() => {
return import("@/components/editor/view-editor");
},
{ ssr: false }
);
export default function FormTeksDetail() {
const MySwal = withReactContent(Swal);
const router = useRouter();
@ -402,12 +410,7 @@ export default function FormTeksDetail() {
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={detail?.description}
onChange={onChange}
className="dark:text-black"
/>
<ViewEditor initialData={detail?.htmlDescription} />
)}
/>
{errors.description?.message && (

View File

@ -51,6 +51,7 @@ import { CloudUpload } from "lucide-react";
import Image from "next/image";
import { error, loading } from "@/config/swal";
import { Item } from "@radix-ui/react-dropdown-menu";
import dynamic from "next/dynamic";
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -70,6 +71,13 @@ type Category = {
name: string;
};
const CustomEditor = dynamic(
() => {
return import("@/components/editor/custom-editor");
},
{ ssr: false }
);
export default function FormTeks() {
const MySwal = withReactContent(Swal);
const router = useRouter();
@ -281,19 +289,47 @@ export default function FormTeks() {
};
const handleArticleIdClick = async (id: string) => {
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
setIsLoading(true); // Tampilkan loading segera setelah ID diklik
try {
// Panggil API untuk mendapatkan data artikel
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
const articleImagesData = articleData?.imagesUrl?.split(",");
// Bersihkan konten articleBody dari elemen gambar
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
// Pisahkan URL gambar menjadi array
const articleImagesData = articleData?.imagesUrl?.split(",");
// Tunggu hingga `articleBody` tidak null atau kosong
const waitForGeneratedBody = async () => {
return new Promise<void>((resolve) => {
const interval = setInterval(() => {
if (cleanArticleBody) {
clearInterval(interval); // Hentikan polling jika articleBody tersedia
resolve();
}
}, 500); // Periksa setiap 500ms
});
};
// Tunggu hingga articleBody selesai di-generate
await waitForGeneratedBody();
// Set data artikel ke state setelah validasi
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
} catch (error) {
console.error("Error fetching article details:", error);
} finally {
// Hilangkan loading setelah semua data selesai di-generate
setIsLoading(false);
}
};
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
@ -861,14 +897,18 @@ export default function FormTeks() {
<Controller
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={articleBody || value}
onChange={onChange}
className="dark:text-black"
/>
)}
render={({ field: { onChange, value } }) =>
isLoading ? (
<div className="flex justify-center items-center h-40">
<p className="text-gray-500">Loading...</p>
</div>
) : (
<CustomEditor
onChange={onChange}
initialData={articleBody || value}
/>
)
}
/>
{errors.description?.message && (
<p className="text-red-400 text-sm">

View File

@ -51,7 +51,14 @@ import { CloudUpload } from "lucide-react";
import Image from "next/image";
import { error, loading } from "@/config/swal";
import { Item } from "@radix-ui/react-dropdown-menu";
import CustomEditor from "@/components/editor/custom-editor";
import dynamic from "next/dynamic";
const CustomEditor = dynamic(
() => {
return import("@/components/editor/custom-editor");
},
{ ssr: false }
);
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -282,19 +289,47 @@ export default function FormVideo() {
};
const handleArticleIdClick = async (id: string) => {
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
setIsLoading(true); // Tampilkan loading segera setelah ID diklik
try {
// Panggil API untuk mendapatkan data artikel
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
const articleImagesData = articleData?.imagesUrl?.split(",");
// Bersihkan konten articleBody dari elemen gambar
const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
// Pisahkan URL gambar menjadi array
const articleImagesData = articleData?.imagesUrl?.split(",");
// Tunggu hingga `articleBody` tidak null atau kosong
const waitForGeneratedBody = async () => {
return new Promise<void>((resolve) => {
const interval = setInterval(() => {
if (cleanArticleBody) {
clearInterval(interval); // Hentikan polling jika articleBody tersedia
resolve();
}
}, 500); // Periksa setiap 500ms
});
};
// Tunggu hingga articleBody selesai di-generate
await waitForGeneratedBody();
// Set data artikel ke state setelah validasi
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
setArticleImages(articleImagesData || []);
} catch (error) {
console.error("Error fetching article details:", error);
} finally {
// Hilangkan loading setelah semua data selesai di-generate
setIsLoading(false);
}
};
const handleAddTag = (e: React.KeyboardEvent<HTMLInputElement>) => {

View File

@ -20,8 +20,12 @@ import {
import { Checkbox } from "@/components/ui/checkbox";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import JoditEditor from "jodit-react";
import { createTask, getTask } from "@/service/task";
import { getContestById } from "@/service/contest/contest";
import {
createTask,
getTask,
getUserLevelForAssignments,
} from "@/service/task";
import { getContestById, postCreateContest } from "@/service/contest/contest";
import page from "@/app/[locale]/page";
import {
Popover,
@ -29,10 +33,19 @@ import {
PopoverTrigger,
} from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { CalendarIcon } from "lucide-react";
import { CalendarIcon, ChevronDown, ChevronUp } from "lucide-react";
import { format, parseISO } from "date-fns";
import { Calendar } from "@/components/ui/calendar";
import { DateRange } from "react-day-picker";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import dynamic from "next/dynamic";
import Cookies from "js-cookie";
const contestSchema = z.object({
theme: z.string().min(1, { message: "Judul diperlukan" }),
@ -40,9 +53,12 @@ const contestSchema = z.object({
description: z.string().min(2, {
message: "Narasi Penugasan harus lebih dari 2 karakter.",
}),
scoringFormula: z.string().min(2, {
message: "Narasi Penugasan harus lebih dari 2 karakter.",
}),
});
export type taskDetail = {
export type contestDetail = {
id: number;
theme: string;
hastagCode: string;
@ -56,12 +72,22 @@ export type taskDetail = {
name: string;
};
createdAt: string;
platformType: string | null;
assignmentTypeId: string;
targetOutput: string;
targetParticipantTopLevel: string;
description: string;
fileTypeOutput: any;
is_active: string;
};
const CustomEditor = dynamic(
() => {
return import("@/components/editor/custom-editor");
},
{ ssr: false }
);
export default function FormContestDetail() {
const MySwal = withReactContent(Swal);
const router = useRouter();
@ -69,8 +95,19 @@ export default function FormContestDetail() {
type ContestSchema = z.infer<typeof contestSchema>;
const { id } = useParams() as { id: string };
console.log(id);
const [mainType, setMainType] = useState<string>("1");
const [broadcastType, setBroadcastType] = useState<string>(""); // untuk Tipe Penugasan
const [selectedTarget, setSelectedTarget] = useState("all");
const [detail, setDetail] = useState<any>();
const [refresh] = useState(false);
const [date, setDate] = useState<DateRange | undefined>();
const [listDest, setListDest] = useState([]);
const [checkedLevels, setCheckedLevels] = useState(new Set());
const [expandedPolda, setExpandedPolda] = useState([{}]);
const [isLoading, setIsLoading] = useState(false);
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
// State for various form fields
const [taskOutput, setTaskOutput] = useState({
all: false,
video: false,
@ -79,18 +116,6 @@ export default function FormContestDetail() {
text: false,
});
// const [assignmentType, setAssignmentType] = useState("mediahub");
// const [assignmentCategory, setAssignmentCategory] = useState("publication");
const [mainType, setMainType] = useState<string>("1");
const [taskType, setTaskType] = useState<string>("atensi-khusus");
const [broadcastType, setBroadcastType] = useState<string>(""); // untuk Tipe Penugasan
const [type, setType] = useState<string>("1");
const [selectedTarget, setSelectedTarget] = useState("all");
const [detail, setDetail] = useState<taskDetail>();
const [refresh] = useState(false);
const [date, setDate] = useState<DateRange | undefined>();
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
const [unitSelection, setUnitSelection] = useState({
allUnit: false,
mabes: false,
@ -113,6 +138,30 @@ export default function FormContestDetail() {
// setPlatformTypeVisible(selectedValue === 2);
// };
useEffect(() => {
async function fetchPoldaPolres() {
setIsLoading(true);
try {
const response = await getUserLevelForAssignments();
setListDest(response?.data?.data.list);
const initialExpandedState = response?.data?.data.list.reduce(
(acc: any, polda: any) => {
acc[polda.id] = false;
return acc;
},
{}
);
setExpandedPolda(initialExpandedState);
console.log("polres", initialExpandedState);
} catch (error) {
console.error("Error fetching Polda/Polres data:", error);
} finally {
setIsLoading(false);
}
}
fetchPoldaPolres();
}, []);
useEffect(() => {
async function initState() {
if (id) {
@ -142,19 +191,42 @@ export default function FormContestDetail() {
}
}, [detail?.targetOutput]);
useEffect(() => {
if (detail?.targetParticipantTopLevel) {
const outputSet = new Set(
detail.targetParticipantTopLevel.split(",").map(Number)
);
setUnitSelection({
allUnit: outputSet.has(0),
mabes: outputSet.has(1),
polda: outputSet.has(2),
polres: outputSet.has(3),
});
}
}, [detail?.targetParticipantTopLevel]);
// useEffect(() => {
// if (detail?.targetParticipantTopLevel) {
// const outputSet = new Set(
// detail.targetParticipantTopLevel.split(",").map(Number)
// );
// setUnitSelection({
// allUnit: outputSet.has(0),
// mabes: outputSet.has(1),
// polda: outputSet.has(2),
// polres: outputSet.has(3),
// });
// }
// }, [detail?.targetParticipantTopLevel]);
const handleCheckboxChange = (levelId: number) => {
setCheckedLevels((prev) => {
const updatedLevels = new Set(prev);
if (updatedLevels.has(levelId)) {
updatedLevels.delete(levelId);
} else {
updatedLevels.add(levelId);
}
return updatedLevels;
});
};
const handlePoldaPolresChange = () => {
return Array.from(checkedLevels).join(","); // Mengonversi Set ke string
};
const toggleExpand = (poldaId: any) => {
setExpandedPolda((prev: any) => ({
...prev,
[poldaId]: !prev[poldaId],
}));
};
const save = async (data: ContestSchema) => {
const fileTypeMapping = {
@ -165,34 +237,53 @@ export default function FormContestDetail() {
text: "5",
};
const unitMapping = {
allUnit: "0",
mabes: "1",
polda: "2",
polres: "3",
};
const assignmentPurposeString = Object.keys(unitSelection)
.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]) // Ambil hanya yang `true`
.map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping]) // Konversi ke nilai string
.join(",");
const requestData = {
const requestData: {
id?: any;
theme: string;
assignedToLevel: any;
assignmentPurpose: any;
hastagCode: string;
description: string;
assignmentMainTypeId: any;
scoringFormula: string;
fileTypeOutput: any;
} = {
...data,
// assignmentType,
// assignmentCategory,
target: selectedTarget,
unitSelection,
assignedToRole: "3",
taskType: taskType,
broadcastType: broadcastType,
assignmentMainTypeId: mainType,
assignmentPurpose: "1",
assignmentTypeId: type,
fileTypeOutput: selectedOutputs,
id: null,
description: data.description,
platformType: "",
hastagCode: data.hastagCode,
theme: data.theme,
description: data.description,
scoringFormula: data.scoringFormula,
assignmentMainTypeId: mainType,
assignedToLevel: handlePoldaPolresChange(),
assignmentPurpose: assignmentPurposeString,
fileTypeOutput: selectedOutputs,
};
// const response = await createTask(requestData);
if (id != undefined) {
requestData.id = id;
}
const response = await postCreateContest(requestData);
console.log("Form Data Submitted:", requestData);
// console.log("response", response);
console.log("response", response);
MySwal.fire({
title: "Sukses",
@ -225,7 +316,6 @@ export default function FormContestDetail() {
<Card>
<div className="px-6 py-6">
<p className="text-lg font-semibold mb-3">Form Contest</p>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="gap-5 mb-5">
<div className="space-y-2">
@ -233,12 +323,12 @@ export default function FormContestDetail() {
<Controller
control={control}
name="hastagCode"
render={({ field }) => (
render={({ field: { onChange, value } }) => (
<Input
size="md"
type="text"
value={field.value}
onChange={field.onChange}
value={detail?.hastagCode || value}
onChange={onChange}
placeholder="Enter hastagCode"
/>
)}
@ -255,12 +345,12 @@ export default function FormContestDetail() {
<Controller
control={control}
name="theme"
render={({ field }) => (
render={({ field: { onChange, value } }) => (
<Input
size="md"
type="text"
value={field.value}
onChange={field.onChange}
value={detail?.theme || value}
onChange={onChange}
placeholder="Enter theme"
/>
)}
@ -345,19 +435,101 @@ export default function FormContestDetail() {
</Label>
</div>
))}
<div className=" pl-1">
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
[Kustom]
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
<DialogHeader>
<DialogTitle>
Daftar Wilayah Polda dan Polres
</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listDest.map((polda: any) => (
<div key={polda.id} className="border p-2">
<Label className="flex items-center">
<Checkbox
checked={checkedLevels.has(polda.id)}
onCheckedChange={() =>
handleCheckboxChange(polda.id)
}
className="mr-3"
/>
{polda.name}
<button
onClick={() => toggleExpand(polda.id)}
className="ml-2 focus:outline-none"
>
{expandedPolda[polda.id] ? (
<ChevronUp size={16} />
) : (
<ChevronDown size={16} />
)}
</button>
</Label>
{expandedPolda[polda.id] && (
<div className="ml-6 mt-2">
<Label className="block">
<Checkbox
checked={polda?.subDestination?.every(
(polres: any) =>
checkedLevels.has(polres.id)
)}
onCheckedChange={(isChecked) => {
const updatedLevels = new Set(
checkedLevels
);
polda?.subDestination?.forEach(
(polres: any) => {
if (isChecked) {
updatedLevels.add(polres.id);
} else {
updatedLevels.delete(polres.id);
}
}
);
setCheckedLevels(updatedLevels);
}}
className="mr-2"
/>
Pilih Semua Polres
</Label>
{polda?.subDestination?.map((polres: any) => (
<Label key={polres.id} className="block mt-1">
<Checkbox
checked={checkedLevels.has(polres.id)}
onCheckedChange={() =>
handleCheckboxChange(polres.id)
}
className="mr-2"
/>
{polres.name}
</Label>
))}
</div>
)}
</div>
))}
</div>
</DialogContent>
</Dialog>
</div>
</div>
</div>
<div className="mt-7">
<Label>Narasi Penugasan</Label>
<Controller
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={value}
<CustomEditor
onChange={onChange}
className="dark:text-black"
initialData={detail?.description || value}
/>
)}
/>
@ -367,6 +539,24 @@ export default function FormContestDetail() {
</p>
)}
</div>
<div className="mt-7">
<Label>Rumus Penilaian</Label>
<Controller
control={control}
name="scoringFormula"
render={({ field: { onChange, value } }) => (
<CustomEditor
onChange={onChange}
initialData={detail?.scoringFormula || value}
/>
)}
/>
{errors.scoringFormula?.message && (
<p className="text-red-400 text-sm">
{errors.scoringFormula.message}
</p>
)}
</div>
</div>
<div className="mt-4">

View File

@ -111,6 +111,7 @@ export default function FormTask() {
const [isVideoUploadFinish, setIsVideoUploadFinish] = useState(false);
const [isTextUploadFinish, setIsTextUploadFinish] = useState(false);
const [isAudioUploadFinish, setIsAudioUploadFinish] = useState(false);
const [voiceNoteLink, setVoiceNoteLink] = useState("");
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
const [unitSelection, setUnitSelection] = useState({
@ -244,52 +245,28 @@ export default function FormTask() {
setIsImageUploadFinish(true);
}
imageFiles?.map(async (item: any, index: number) => {
await uploadResumableFile(
index,
String(id),
item,
"1",
"0"
);
await uploadResumableFile(index, String(id), item, "1", "0");
});
if (videoFiles?.length == 0) {
setIsVideoUploadFinish(true);
}
videoFiles?.map(async (item: any, index: number) => {
await uploadResumableFile(
index,
String(id),
item,
"2",
"0"
);
await uploadResumableFile(index, String(id), item, "2", "0");
});
if (textFiles?.length == 0) {
setIsTextUploadFinish(true);
}
textFiles?.map(async (item: any, index: number) => {
await uploadResumableFile(
index,
String(id),
item,
"3",
"0"
);
await uploadResumableFile(index, String(id), item, "3", "0");
});
if (audioFiles?.length == 0) {
setIsAudioUploadFinish(true);
}
audioFiles?.map(async (item: any, index: number) => {
await uploadResumableFile(
index,
String(id),
item,
"4",
"0"
);
await uploadResumableFile(index, String(id), item, "4", "0");
});
// MySwal.fire({
@ -372,11 +349,11 @@ export default function FormTask() {
};
async function uploadResumableFile(
idx: number,
id: string,
file: any,
fileTypeId: string,
duration: string
idx: number,
id: string,
file: any,
fileTypeId: string,
duration: string
) {
console.log(idx, id, file, fileTypeId, duration);
@ -417,13 +394,15 @@ export default function FormTask() {
// counterUpdateProgress++;
// setCounterProgress(counterUpdateProgress);
successTodo();
if (fileTypeId == '1'){
if (fileTypeId == "1") {
setIsImageUploadFinish(true);
} else if (fileTypeId == '2'){
} else if (fileTypeId == "2") {
setIsVideoUploadFinish(true);
} if (fileTypeId == '3'){
}
if (fileTypeId == "3") {
setIsTextUploadFinish(true);
} if (fileTypeId == '4'){
}
if (fileTypeId == "4") {
setIsAudioUploadFinish(true);
}
},
@ -431,17 +410,27 @@ export default function FormTask() {
upload.start();
}
useEffect(() => {
successTodo();
}, [isImageUploadFinish, isVideoUploadFinish, isAudioUploadFinish, isTextUploadFinish])
}, [
isImageUploadFinish,
isVideoUploadFinish,
isAudioUploadFinish,
isTextUploadFinish,
]);
function successTodo() {
if (isImageUploadFinish && isVideoUploadFinish && isAudioUploadFinish && isTextUploadFinish) {
if (
isImageUploadFinish &&
isVideoUploadFinish &&
isAudioUploadFinish &&
isTextUploadFinish
) {
successSubmit("/in/contributor/agenda-setting");
}
}
const successSubmit = (redirect: string) => {
MySwal.fire({
title: "Sukses",
@ -454,7 +443,6 @@ export default function FormTask() {
});
};
return (
<Card>
<div className="px-6 py-6">
@ -709,7 +697,7 @@ export default function FormTask() {
<div className="space-y-3">
<div>
<Label>Video</Label>
<FileUploader
<FileUploader
accept={{
"mp4/*": [],
"mov/*": [],
@ -721,7 +709,7 @@ export default function FormTask() {
</div>
<div>
<Label>Foto</Label>
<FileUploader
<FileUploader
accept={{
"image/*": [],
}}
@ -732,7 +720,7 @@ export default function FormTask() {
</div>
<div>
<Label>Teks</Label>
<FileUploader
<FileUploader
accept={{
"pdf/*": [],
}}
@ -752,7 +740,7 @@ export default function FormTask() {
downloadOnSavePress={true}
downloadFileExtension="webm"
/>
<FileUploader
<FileUploader
accept={{
"mp3/*": [],
"wav/*": [],
@ -776,10 +764,18 @@ export default function FormTask() {
</Button>
</div>
)}
{isRecording && (
<p>Recording... {timer} seconds remaining</p>
)}{" "}
{isRecording && <p>Recording... {timer} seconds remaining</p>}{" "}
{/* Display remaining time */}
<div className="mt-4">
<Label htmlFor="voiceNoteLink">Link Berita</Label>
<Input
id="voiceNoteLink"
type="url"
placeholder="Masukkan link voice note"
value={voiceNoteLink}
onChange={(e) => setVoiceNoteLink(e.target.value)}
/>
</div>
</div>
</div>
</div>

View File

@ -44,7 +44,6 @@ export async function listDataAll(
);
}
<<<<<<< HEAD
export async function listDataImage(
limit: any,
page: any,
@ -59,15 +58,11 @@ export async function listDataImage(
endDate: any,
title: string = ""
) {
=======
export async function listDataImage(limit: any, page: any, isForSelf: any, isApproval: any, categoryFilter: any, statusFilter: any, needApprovalFromLevel: any, creator: any, source: any, startDate: any, endDate: any, title: string = "") {
>>>>>>> e2193a8c9ac305726ea8f34d9b99e36b010f6841
return await httpGetInterceptor(
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=1&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);
}
<<<<<<< HEAD
export async function listDataVideo(
limit: any,
page: any,
@ -82,15 +77,11 @@ export async function listDataVideo(
endDate: any,
title: string = ""
) {
=======
export async function listDataVideo(limit: any, page: any, isForSelf: any, isApproval: any, categoryFilter: any, statusFilter: any, needApprovalFromLevel: any, creator: any, source: any, startDate: any, endDate: any, title: string = "") {
>>>>>>> e2193a8c9ac305726ea8f34d9b99e36b010f6841
return await httpGetInterceptor(
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=2&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);
}
<<<<<<< HEAD
export async function listDataTeks(
limit: any,
page: any,
@ -105,18 +96,14 @@ export async function listDataTeks(
endDate: any,
title: string = ""
) {
=======
export async function listDataTeks(limit: any, page: any, isForSelf: any, isApproval: any, categoryFilter: any, statusFilter: any, needApprovalFromLevel: any, creator: any, source: any, startDate: any, endDate: any, title: string = "") {
>>>>>>> e2193a8c9ac305726ea8f34d9b99e36b010f6841
return await httpGetInterceptor(
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=3&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);
}
<<<<<<< HEAD
export async function listDataAudio(
page: any,
limit: any,
page: any,
isForSelf: any,
isApproval: any,
categoryFilter: any,
@ -128,9 +115,6 @@ export async function listDataAudio(
endDate: any,
title: string = ""
) {
=======
export async function listDataAudio(page: any, limit: any, isForSelf: any, isApproval: any, categoryFilter: any, statusFilter: any, needApprovalFromLevel: any, creator: any, source: any, startDate: any, endDate: any, title: string = "") {
>>>>>>> e2193a8c9ac305726ea8f34d9b99e36b010f6841
return await httpGetInterceptor(
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=4&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);

View File

@ -22,3 +22,8 @@ export async function getContestById(id: any, pages = 0) {
const url = `contest?id=${id}&page=${pages}`;
return httpGetInterceptor(url);
}
export async function postCreateContest(data: any) {
const url = "contest";
return httpPostInterceptor(url, data);
}