Refactor internify components and services
- Updated LoginInternify to remove unnecessary state initialization. - Cleaned up NotificationList by removing unused code and fixing button click handler. - Added project_id prop to InternClaimCert for better data handling. - Enhanced CertificateNotAvailable to include claim functionality with loading and error states. - Modified HomeHeader to display a default user name. - Corrected ProjectTimeline to import ProjectTask from the correct type file. - Implemented loading and error handling in CertificateListPage. - Improved MentorProjectDetailPage to handle task updates and navigation correctly. - Enhanced MentorSettingsPage to manage profile picture errors and state. - Updated AddInternsDialog to use the correct hook for fetching interns. - Refactored EditSubmissionTask to handle task updates and errors more effectively. - Improved MentorProjectCard to include project archiving functionality. - Removed deprecated useInterns hook and replaced it with useUser for fetching user data. - Added new useMentors hook for managing mentor-related operations. - Cleaned up CertificateService by removing unused verifyCertificate function. - Created MentorServices for managing mentor data operations. - Updated UserService to include fetching Mahasiswa data and removed unused UserServices file.
This commit is contained in:
@@ -65,6 +65,7 @@ const SertificatePage = () => {
|
||||
progress={progress}
|
||||
remainingTasks={remainingTasks}
|
||||
allTasksDone={allTasksDone}
|
||||
project_id={project?.id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
import { Clock, Lock, Award } from "lucide-react";
|
||||
import { useClaimCertificate } from "../../../../hooks/useSertificates";
|
||||
|
||||
interface CertificateNotAvailableProps {
|
||||
progress: number;
|
||||
remainingTasks: number;
|
||||
allTasksDone?: boolean;
|
||||
project_id?: number;
|
||||
}
|
||||
|
||||
export default function CertificateNotAvailable({
|
||||
progress,
|
||||
remainingTasks,
|
||||
allTasksDone = false,
|
||||
project_id
|
||||
}: CertificateNotAvailableProps) {
|
||||
|
||||
const { claim, loading, error } = useClaimCertificate();
|
||||
|
||||
const handleClaim = async () => {
|
||||
if (!project_id) return;
|
||||
await claim(project_id);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-box-primary w-full h-full rounded-2xl border border-box-border shadow-sm px-24 py-12 flex flex-col items-center justify-center">
|
||||
{/* Icon */}
|
||||
@@ -59,9 +70,9 @@ export default function CertificateNotAvailable({
|
||||
|
||||
{/* Progress Bar */}
|
||||
<div className="w-1/3">
|
||||
<p className="text-xs text-font mt-2">
|
||||
Selesaikan {remainingTasks} tugas lagi untuk membuka akses.
|
||||
</p>
|
||||
<p className="text-xs text-font mt-2">
|
||||
Selesaikan {remainingTasks} tugas lagi untuk membuka akses.
|
||||
</p>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-sm font-semibold text-gray-700">Progres Proyek</span>
|
||||
<span className="text-sm font-bold text-red-700">{progress}%</span>
|
||||
@@ -72,8 +83,17 @@ export default function CertificateNotAvailable({
|
||||
style={{ width: `${progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleClaim}
|
||||
disabled={loading}
|
||||
className="mt-2 px-6 py-2.5 bg-green-600 hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed text-white font-semibold rounded-lg transition-colors duration-200"
|
||||
>
|
||||
{loading ? "Memproses..." : "Klaim Sertifikat"}
|
||||
</button>
|
||||
|
||||
{error && <p className="text-red-500 text-sm mt-2">{error}</p>}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ const HomeHeader = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-start px-0 mb-5">
|
||||
<h1 className="page-title">Hi, {name || "..."}!</h1>
|
||||
<h1 className="page-title">Hi, {name || "User"}!</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ProjectTask } from "../../../../types/project.types";
|
||||
import type { ProjectTask } from "../../../../types/task.types";
|
||||
|
||||
const formatDate = (dateStr: string) =>
|
||||
new Date(dateStr).toLocaleDateString('id-ID', { day: 'numeric', month: 'short' });
|
||||
@@ -6,22 +6,24 @@ const formatDate = (dateStr: string) =>
|
||||
export default function ProjectTimeline({ tasks }: { tasks: ProjectTask[] }) {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex items-center gap-1.5 mb-4 justify-between">
|
||||
<span className="font-semibold text-md text-font-shade">Timeline</span>
|
||||
</div>
|
||||
<ul className="relative pl-4">
|
||||
{tasks.map((task) => {
|
||||
{tasks.map((task, index) => {
|
||||
const d = new Date(task.deadline_at);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
const isToday = d.getTime() === today.getTime();
|
||||
const isPast = d < today;
|
||||
const active = isToday || isPast;
|
||||
|
||||
return (
|
||||
<li key={task.id} className="relative mb-6 list-none">
|
||||
{/* Vertical line ke bawah, kecuali item terakhir */}
|
||||
{index < tasks.length - 1 && (
|
||||
<div className="absolute -left-[1.0625rem] top-3 w-px h-full bg-[#ddd]" />
|
||||
)}
|
||||
{/* Dot */}
|
||||
<div
|
||||
className={`absolute -left-5 top-0.5 w-3 h-3 rounded-full border-2 border-white ${
|
||||
@@ -29,7 +31,7 @@ export default function ProjectTimeline({ tasks }: { tasks: ProjectTask[] }) {
|
||||
} ${isToday ? 'shadow-md' : ''}`}
|
||||
/>
|
||||
<div className={`text-[11px] font-semibold ${isToday ? 'text-[#C0392B]' : 'text-[#888]'}`}>
|
||||
{isToday ? 'Hari ini' : formatDate(task.deadline_at)} {/* ← format ISO string */}
|
||||
{isToday ? 'Hari ini' : formatDate(task.deadline_at)}
|
||||
</div>
|
||||
<div className="text-xs text-[#555] mt-px leading-[1.3]">
|
||||
{task.title}
|
||||
|
||||
Reference in New Issue
Block a user