Merge branch 'dev-sabda-v2' of https://gitlab.com/hanifsalafi/mediahub_redesign
This commit is contained in:
commit
933a672280
|
|
@ -22,7 +22,7 @@ import withReactContent from "sweetalert2-react-content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const useTableColumns = (activeTab: "ta" | "daily" | "special") => {
|
const useTableColumns = (activeTab: "ta" | "daily" | "special" |"mabes-koor") => {
|
||||||
const t = useTranslations("Table");
|
const t = useTranslations("Table");
|
||||||
const columns: ColumnDef<any>[] = [
|
const columns: ColumnDef<any>[] = [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -43,7 +43,7 @@ import { getCsrfToken } from "@/service/auth";
|
||||||
import { loading } from "@/lib/swal";
|
import { loading } from "@/lib/swal";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
||||||
import {
|
import {
|
||||||
Popover,
|
Popover,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
|
|
@ -181,6 +181,33 @@ export default function FormTaskTa() {
|
||||||
mode: "all",
|
mode: "all",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [profile, setProfile] = useState<any>(null);
|
||||||
|
const userLevelId = Number(getCookiesDecrypt("ulie"));
|
||||||
|
const roleId = Number(getCookiesDecrypt("urie"));
|
||||||
|
const userId = Number(getCookiesDecrypt("uie"));
|
||||||
|
|
||||||
|
const MABES_LEVEL_ID = 216; // userLevelId Mabes Polri
|
||||||
|
const APPROVER_ROLE_ID = 3; // roleId Approver
|
||||||
|
const isMabes = userLevelId === MABES_LEVEL_ID;
|
||||||
|
const isApprover = roleId === APPROVER_ROLE_ID;
|
||||||
|
|
||||||
|
const isMabesApprover =
|
||||||
|
userLevelId === MABES_LEVEL_ID && roleId === APPROVER_ROLE_ID;
|
||||||
|
|
||||||
|
const shouldHideExpert = isMabes && isApprover;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchUserLevel() {
|
||||||
|
try {
|
||||||
|
const res = await getUserLevelForAssignments();
|
||||||
|
setProfile(res?.data?.data);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed fetch user level", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchUserLevel();
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getDataAdditional();
|
getDataAdditional();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -352,55 +379,126 @@ export default function FormTaskTa() {
|
||||||
// // });
|
// // });
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
// const save = async (data: TaskSchema) => {
|
||||||
|
// const cleanedLinks = links
|
||||||
|
// .map((link) => link.trim())
|
||||||
|
// .filter((link) => link.startsWith("http"));
|
||||||
|
|
||||||
|
// const requestData = {
|
||||||
|
// ...data,
|
||||||
|
// // assignedToUsers: handleExpertChange(),
|
||||||
|
// assignedToUsers: isMabesApprover ? "464" : handleExpertChange(),
|
||||||
|
// assignmentType: taskType,
|
||||||
|
// assignmentTypeId: type,
|
||||||
|
// expertCompetencies: Array.from(selectedCompetencies).join(","),
|
||||||
|
// attachmentUrl: cleanedLinks,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// console.log("FINAL ASSIGNED TO:", {
|
||||||
|
// isMabesApprover,
|
||||||
|
// assignedToUsers: isMabesApprover
|
||||||
|
// ? String(roleId)
|
||||||
|
// : handleExpertChange(),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const response = await createTaskTa(requestData);
|
||||||
|
// const id = String(response?.data?.data.id);
|
||||||
|
|
||||||
|
// // Set block table TA
|
||||||
|
// localStorage.setItem("TA_UPLOAD_IN_PROGRESS", "true");
|
||||||
|
|
||||||
|
// loading(); // SHOW SWAL LOADING
|
||||||
|
|
||||||
|
// // Kumpulkan semua upload
|
||||||
|
// const allUploads: Promise<any>[] = [];
|
||||||
|
|
||||||
|
// imageFiles.forEach((item, idx) =>
|
||||||
|
// allUploads.push(uploadResumableFile(idx, id, item, "1", "0"))
|
||||||
|
// );
|
||||||
|
|
||||||
|
// videoFiles.forEach((item, idx) =>
|
||||||
|
// allUploads.push(uploadResumableFile(idx, id, item, "2", "0"))
|
||||||
|
// );
|
||||||
|
|
||||||
|
// textFiles.forEach((item, idx) =>
|
||||||
|
// allUploads.push(uploadResumableFile(idx, id, item, "3", "0"))
|
||||||
|
// );
|
||||||
|
|
||||||
|
// audioFiles.forEach((item, idx) =>
|
||||||
|
// allUploads.push(uploadResumableFile(idx, id, item, "4", "0"))
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // Tunggu upload selesai
|
||||||
|
// await Promise.all(allUploads);
|
||||||
|
|
||||||
|
// // Hapus flag
|
||||||
|
// localStorage.removeItem("TA_UPLOAD_IN_PROGRESS");
|
||||||
|
|
||||||
|
// // Close loading + redirect
|
||||||
|
// successSubmit("/in/contributor/task-ta");
|
||||||
|
// };
|
||||||
|
|
||||||
const save = async (data: TaskSchema) => {
|
const save = async (data: TaskSchema) => {
|
||||||
const cleanedLinks = links
|
try {
|
||||||
.map((link) => link.trim())
|
loading();
|
||||||
.filter((link) => link.startsWith("http"));
|
|
||||||
|
|
||||||
const requestData = {
|
const cleanedLinks = links
|
||||||
...data,
|
.map((link) => link.trim())
|
||||||
assignedToUsers: handleExpertChange(),
|
.filter((link) => link.startsWith("http"));
|
||||||
assignmentType: taskType,
|
|
||||||
assignmentTypeId: type,
|
|
||||||
expertCompetencies: Array.from(selectedCompetencies).join(","),
|
|
||||||
attachmentUrl: cleanedLinks,
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await createTaskTa(requestData);
|
const requestData = {
|
||||||
const id = String(response?.data?.data.id);
|
...data,
|
||||||
|
// assignedToUsers: isMabesApprover ? "464" : handleExpertChange(),
|
||||||
|
assignedToUsers: isMabesApprover
|
||||||
|
? ["464", "8258"]
|
||||||
|
: handleExpertChange(),
|
||||||
|
assignmentType: taskType,
|
||||||
|
assignmentTypeId: type,
|
||||||
|
expertCompetencies: Array.from(selectedCompetencies).join(","),
|
||||||
|
attachmentUrl: cleanedLinks,
|
||||||
|
};
|
||||||
|
|
||||||
// Set block table TA
|
const response = await createTaskTa(requestData);
|
||||||
localStorage.setItem("TA_UPLOAD_IN_PROGRESS", "true");
|
|
||||||
|
|
||||||
loading(); // SHOW SWAL LOADING
|
if (!response?.data?.data?.id) {
|
||||||
|
throw new Error("Gagal membuat task");
|
||||||
|
}
|
||||||
|
|
||||||
// Kumpulkan semua upload
|
const assignmentId = String(response.data.data.id);
|
||||||
const allUploads: Promise<any>[] = [];
|
|
||||||
|
|
||||||
imageFiles.forEach((item, idx) =>
|
const uploads: Promise<any>[] = [];
|
||||||
allUploads.push(uploadResumableFile(idx, id, item, "1", "0"))
|
|
||||||
);
|
|
||||||
|
|
||||||
videoFiles.forEach((item, idx) =>
|
imageFiles.forEach((file, i) =>
|
||||||
allUploads.push(uploadResumableFile(idx, id, item, "2", "0"))
|
uploads.push(uploadResumableFile(i, assignmentId, file, "1", "0"))
|
||||||
);
|
);
|
||||||
|
|
||||||
textFiles.forEach((item, idx) =>
|
videoFiles.forEach((file, i) =>
|
||||||
allUploads.push(uploadResumableFile(idx, id, item, "3", "0"))
|
uploads.push(uploadResumableFile(i, assignmentId, file, "2", "0"))
|
||||||
);
|
);
|
||||||
|
|
||||||
audioFiles.forEach((item, idx) =>
|
textFiles.forEach((file, i) =>
|
||||||
allUploads.push(uploadResumableFile(idx, id, item, "4", "0"))
|
uploads.push(uploadResumableFile(i, assignmentId, file, "3", "0"))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Tunggu upload selesai
|
audioFiles.forEach((file, i) =>
|
||||||
await Promise.all(allUploads);
|
uploads.push(uploadResumableFile(i, assignmentId, file, "4", "0"))
|
||||||
|
);
|
||||||
|
|
||||||
// Hapus flag
|
await Promise.all(uploads);
|
||||||
localStorage.removeItem("TA_UPLOAD_IN_PROGRESS");
|
|
||||||
|
|
||||||
// Close loading + redirect
|
successSubmit("/in/contributor/task-ta");
|
||||||
successSubmit("/in/contributor/task-ta");
|
} catch (err: any) {
|
||||||
|
console.error("SUBMIT ERROR:", err);
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Gagal",
|
||||||
|
text:
|
||||||
|
err?.response?.data?.message ||
|
||||||
|
err?.message ||
|
||||||
|
"Terjadi kesalahan, data tidak tersimpan",
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = (data: TaskSchema) => {
|
const onSubmit = (data: TaskSchema) => {
|
||||||
|
|
@ -543,46 +641,91 @@ export default function FormTaskTa() {
|
||||||
|
|
||||||
// upload.start();
|
// upload.start();
|
||||||
// }
|
// }
|
||||||
|
// function uploadResumableFile(
|
||||||
|
// idx: number,
|
||||||
|
// id: string,
|
||||||
|
// file: any,
|
||||||
|
// fileTypeId: string,
|
||||||
|
// duration: string
|
||||||
|
// ) {
|
||||||
|
// return new Promise(async (resolve, reject) => {
|
||||||
|
// const resCsrf = await getCsrfToken();
|
||||||
|
// const csrfToken = resCsrf?.data?.token;
|
||||||
|
|
||||||
|
// const upload = new Upload(file, {
|
||||||
|
// endpoint: `${process.env.NEXT_PUBLIC_API}/assignment-expert/file/upload`,
|
||||||
|
// headers: { "X-XSRF-TOKEN": csrfToken },
|
||||||
|
// retryDelays: [0, 3000, 6000, 12000],
|
||||||
|
// chunkSize: 20000,
|
||||||
|
// metadata: {
|
||||||
|
// assignmentId: id,
|
||||||
|
// filename: file.name,
|
||||||
|
// contentType: file.type,
|
||||||
|
// fileTypeId,
|
||||||
|
// duration,
|
||||||
|
// },
|
||||||
|
|
||||||
|
// onBeforeRequest(req) {
|
||||||
|
// req.getUnderlyingObject().withCredentials = true;
|
||||||
|
// },
|
||||||
|
|
||||||
|
// onError(err) {
|
||||||
|
// console.error("Upload error:", err);
|
||||||
|
// reject(err);
|
||||||
|
// },
|
||||||
|
|
||||||
|
// onSuccess() {
|
||||||
|
// console.log("Upload selesai:", file.name);
|
||||||
|
// resolve(true);
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// upload.start();
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
function uploadResumableFile(
|
function uploadResumableFile(
|
||||||
idx: number,
|
idx: number,
|
||||||
id: string,
|
id: string,
|
||||||
file: any,
|
file: File,
|
||||||
fileTypeId: string,
|
fileTypeId: string,
|
||||||
duration: string
|
duration: string
|
||||||
) {
|
) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const resCsrf = await getCsrfToken();
|
try {
|
||||||
const csrfToken = resCsrf?.data?.token;
|
const resCsrf = await getCsrfToken();
|
||||||
|
const csrfToken = resCsrf?.data?.token;
|
||||||
|
|
||||||
const upload = new Upload(file, {
|
const upload = new Upload(file, {
|
||||||
endpoint: `${process.env.NEXT_PUBLIC_API}/assignment-expert/file/upload`,
|
endpoint: `${process.env.NEXT_PUBLIC_API}/assignment-expert/file/upload`,
|
||||||
headers: { "X-XSRF-TOKEN": csrfToken },
|
headers: { "X-XSRF-TOKEN": csrfToken },
|
||||||
retryDelays: [0, 3000, 6000, 12000],
|
retryDelays: [0, 3000, 6000],
|
||||||
chunkSize: 20000,
|
chunkSize: 20000,
|
||||||
metadata: {
|
metadata: {
|
||||||
assignmentId: id,
|
assignmentId: id,
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
contentType: file.type,
|
contentType: file.type,
|
||||||
fileTypeId,
|
fileTypeId,
|
||||||
duration,
|
duration,
|
||||||
},
|
},
|
||||||
|
|
||||||
onBeforeRequest(req) {
|
onBeforeRequest(req) {
|
||||||
req.getUnderlyingObject().withCredentials = true;
|
req.getUnderlyingObject().withCredentials = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
onError(err) {
|
onError(error) {
|
||||||
console.error("Upload error:", err);
|
reject(error);
|
||||||
reject(err);
|
},
|
||||||
},
|
|
||||||
|
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
console.log("Upload selesai:", file.name);
|
resolve(true);
|
||||||
resolve(true);
|
},
|
||||||
},
|
});
|
||||||
});
|
|
||||||
|
|
||||||
upload.start();
|
upload.start();
|
||||||
|
} catch (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -718,101 +861,109 @@ export default function FormTaskTa() {
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 space-y-2">
|
{!isMabesApprover && (
|
||||||
<Label>
|
<div className="mt-5 space-y-2">
|
||||||
{t("areas-expertise", { defaultValue: "Areas Expertise" })}
|
<Label>
|
||||||
</Label>
|
{t("areas-expertise", { defaultValue: "Areas Expertise" })}
|
||||||
<div className="flex flex-wrap gap-4">
|
</Label>
|
||||||
{userCompetencies?.map((item: any) => (
|
<div className="flex flex-wrap gap-4">
|
||||||
<div className="flex items-center gap-2" key={item.id}>
|
{userCompetencies?.map((item: any) => (
|
||||||
<Checkbox
|
<div className="flex items-center gap-2" key={item.id}>
|
||||||
id={`comp-${item.id}`}
|
<Checkbox
|
||||||
checked={selectedCompetencies.has(item.id)}
|
id={`comp-${item.id}`}
|
||||||
onCheckedChange={() => handleCompetencyChange(item.id)}
|
checked={selectedCompetencies.has(item.id)}
|
||||||
/>
|
onCheckedChange={() => handleCompetencyChange(item.id)}
|
||||||
<Label htmlFor={`comp-${item.id}`}>{item.name}</Label>
|
/>
|
||||||
</div>
|
<Label htmlFor={`comp-${item.id}`}>{item.name}</Label>
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-5 space-y-2">
|
|
||||||
<Label>
|
|
||||||
{t("choose-expert", { defaultValue: "Choose Expert" })}
|
|
||||||
</Label>
|
|
||||||
<div className="flex flex-wrap gap-4">
|
|
||||||
<Dialog>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Button variant="soft" size="sm" color="primary">
|
|
||||||
[{"Pilih Tenaga Ahli"}]
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Daftar Tenaga Ahli</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
|
|
||||||
{listExpert?.map((expert: any) => (
|
|
||||||
<div key={expert.id} className="border p-2">
|
|
||||||
<Label className="flex items-center">
|
|
||||||
<Checkbox
|
|
||||||
checked={checkedLevels.has(expert.id)}
|
|
||||||
onCheckedChange={() =>
|
|
||||||
handleCheckboxChange(expert.id)
|
|
||||||
}
|
|
||||||
className="mr-3"
|
|
||||||
/>
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<div className="font-bold">{expert.fullname}</div>
|
|
||||||
<div className="italic">({expert.username})</div>
|
|
||||||
</div>
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
))}
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
{checkedLevels.size > 0 && (
|
|
||||||
<div className="mt-3">
|
|
||||||
<Label className="text-sm text-gray-600 mb-2 block">
|
|
||||||
Tenaga Ahli Terpilih ({checkedLevels.size})
|
|
||||||
</Label>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
{Array.from(checkedLevels).map((expertId) => {
|
|
||||||
const expert = listExpert?.find(
|
|
||||||
(exp: any) => exp.id === expertId
|
|
||||||
);
|
|
||||||
return expert ? (
|
|
||||||
<div
|
|
||||||
key={expert.id}
|
|
||||||
className="inline-flex items-center gap-2 bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1.5 rounded-full border border-blue-200"
|
|
||||||
>
|
|
||||||
<span>{expert.fullname}</span>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleCheckboxChange(expert.id)}
|
|
||||||
className="ml-1 text-blue-600 hover:text-blue-800 hover:bg-blue-200 rounded-full p-0.5 transition-colors"
|
|
||||||
title="Remove expert"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
className="w-3 h-3"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : null;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
{!isMabesApprover && (
|
||||||
|
<div className="mt-5 space-y-2">
|
||||||
|
<Label>
|
||||||
|
{t("choose-expert", { defaultValue: "Choose Expert" })}
|
||||||
|
</Label>
|
||||||
|
<div className="flex flex-wrap gap-4">
|
||||||
|
<Dialog>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="soft" size="sm" color="primary">
|
||||||
|
[{"Pilih Tenaga Ahli"}]
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Daftar Tenaga Ahli</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
|
||||||
|
{listExpert?.map((expert: any) => (
|
||||||
|
<div key={expert.id} className="border p-2">
|
||||||
|
<Label className="flex items-center">
|
||||||
|
<Checkbox
|
||||||
|
checked={checkedLevels.has(expert.id)}
|
||||||
|
onCheckedChange={() =>
|
||||||
|
handleCheckboxChange(expert.id)
|
||||||
|
}
|
||||||
|
className="mr-3"
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<div className="font-bold">
|
||||||
|
{expert.fullname}
|
||||||
|
</div>
|
||||||
|
<div className="italic">
|
||||||
|
({expert.username})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
{checkedLevels.size > 0 && (
|
||||||
|
<div className="mt-3">
|
||||||
|
<Label className="text-sm text-gray-600 mb-2 block">
|
||||||
|
Tenaga Ahli Terpilih ({checkedLevels.size})
|
||||||
|
</Label>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{Array.from(checkedLevels).map((expertId) => {
|
||||||
|
const expert = listExpert?.find(
|
||||||
|
(exp: any) => exp.id === expertId
|
||||||
|
);
|
||||||
|
return expert ? (
|
||||||
|
<div
|
||||||
|
key={expert.id}
|
||||||
|
className="inline-flex items-center gap-2 bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1.5 rounded-full border border-blue-200"
|
||||||
|
>
|
||||||
|
<span>{expert.fullname}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleCheckboxChange(expert.id)}
|
||||||
|
className="ml-1 text-blue-600 hover:text-blue-800 hover:bg-blue-200 rounded-full p-0.5 transition-colors"
|
||||||
|
title="Remove expert"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="w-3 h-3"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="mt-5 space-y-2">
|
<div className="mt-5 space-y-2">
|
||||||
<Label>{t("description", { defaultValue: "Description" })}</Label>
|
<Label>{t("description", { defaultValue: "Description" })}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
|
|
@ -946,7 +1097,9 @@ export default function FormTaskTa() {
|
||||||
<Input
|
<Input
|
||||||
type="url"
|
type="url"
|
||||||
className="border rounded p-2 w-full"
|
className="border rounded p-2 w-full"
|
||||||
placeholder={`Masukkan link berita ${index + 1}`}
|
placeholder={`Masukkan link berita ${
|
||||||
|
index + 1
|
||||||
|
} | Contoh: https://www.detik.com`}
|
||||||
value={link}
|
value={link}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleLinkChange(index, e.target.value)
|
handleLinkChange(index, e.target.value)
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,13 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
href: "/contributor/task-ta",
|
||||||
|
label: "penugasan TA",
|
||||||
|
active: pathname.includes("/contributor/task-ta"),
|
||||||
|
icon: "heroicons:shopping-cart",
|
||||||
|
children: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue