feat: add react-hot-toast for notifications, enhance project detail page, and update task handling
- Added `react-hot-toast` dependency for improved notification handling. - Introduced `MentorProjectsDetailPage` for detailed project and task views. - Updated routing to include task-specific paths. - Enhanced breadcrumb navigation to reflect new project structure. - Refactored task handling in `MentorTaskCard` and `ProjectTimeline` components. - Updated mock data to include detailed task submissions and deadlines. - Improved UI elements for better user experience in project management.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { Project } from '../../../lib/mockData';
|
||||
import type { Project } from '../../../lib/mockProjects';
|
||||
import ProjectTimeline from './components/ProjectTimeline';
|
||||
import TaskCard from './components/ProjectTaskCard';
|
||||
import HeroProject from './components/Hero-project';
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function ProjectDetailPage() {
|
||||
}`;
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div>
|
||||
<div>
|
||||
{/* Tabs */}
|
||||
<div className="flex mb-4">
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
||||
import { DEADLINES } from '../../../../lib/mockDeadline'
|
||||
|
||||
interface Deadline {
|
||||
date: number
|
||||
month: number
|
||||
year: number
|
||||
label: string
|
||||
}
|
||||
|
||||
const DEADLINES: Deadline[] = [
|
||||
{ date: 30, month: 6, year: 2026, label: 'Tenggat Proyek Internify Internify - 4 May' },
|
||||
]
|
||||
|
||||
const DAY_LABELS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
|
||||
const MONTH_NAMES = [
|
||||
@@ -19,7 +10,7 @@ const MONTH_NAMES = [
|
||||
]
|
||||
|
||||
function getDaysInMonth(year: number, month: number) {
|
||||
return new Date(year, month+1, 0).getDate()
|
||||
return new Date(year, month + 1, 0).getDate()
|
||||
}
|
||||
|
||||
function getFirstDayOfMonth(year: number, month: number) {
|
||||
@@ -27,7 +18,7 @@ function getFirstDayOfMonth(year: number, month: number) {
|
||||
}
|
||||
|
||||
const HomeCalendar = () => {
|
||||
const [today, setToday] = useState(new Date())
|
||||
const [today, setToday] = useState(new Date())
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
@@ -67,11 +58,18 @@ const [today, setToday] = useState(new Date())
|
||||
currentYear === today.getFullYear()
|
||||
|
||||
const hasDeadline = (day: number) =>
|
||||
DEADLINES.some(d => d.date === day && d.month - 1 === currentMonth && d.year === currentYear)
|
||||
DEADLINES.some(d =>
|
||||
d.date.getDate() === day &&
|
||||
d.date.getMonth() === currentMonth &&
|
||||
d.date.getFullYear() === currentYear
|
||||
)
|
||||
|
||||
const upcomingDeadlines = DEADLINES.filter(
|
||||
d => d.month === currentMonth && d.year === currentYear
|
||||
)
|
||||
const upcomingDeadlines = DEADLINES.filter(d => {
|
||||
return (
|
||||
d.date.getMonth() === currentMonth &&
|
||||
d.date.getFullYear() === currentYear
|
||||
);
|
||||
}).sort((a, b) => a.date.getTime() - b.date.getTime());
|
||||
|
||||
// Previous month trailing days
|
||||
const prevMonthDays = getDaysInMonth(currentYear, currentMonth - 1 < 0 ? 11 : currentMonth - 1)
|
||||
@@ -135,16 +133,16 @@ const [today, setToday] = useState(new Date())
|
||||
|
||||
{/* Current month days */}
|
||||
{currentDays.map(day => (
|
||||
<div key={day} className="flex justify-center items-center py-1 px-4">
|
||||
<div key={day} className="flex justify-center items-center py-0.5">
|
||||
{isToday(day) ? (
|
||||
<span className="w-8 h-7 flex items-center justify-center border-b-2 border-red-800 text-xs font-semibold">
|
||||
{day}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
className={`w-full h-7 flex items-center justify-center text-xs rounded
|
||||
className={`w-full h-7 flex items-center justify-center text-xs
|
||||
${isBold(day) ? 'font-bold text-gray-800' : 'text-gray-700'}
|
||||
${hasDeadline(day) ? 'bg-red-700 text-white' : ''}
|
||||
${hasDeadline(day) ? 'bg-red-800 text-white' : ''}
|
||||
transition-colors`}
|
||||
>
|
||||
{day}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Task } from "../../../../lib/mockData";
|
||||
import type { Task } from "../../../../lib/mockProjects";
|
||||
import { ArrowDownNarrowWide } from "lucide-react";
|
||||
|
||||
const formatDate = (date: Date) =>
|
||||
@@ -11,7 +11,7 @@ export default function ProjectTimeline({ tasks }: { tasks: Task[] }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-4 justify-between">
|
||||
<span className="font-semibold text-sm text-[#1a1a1a]">
|
||||
<span className="font-semibold text-md text-[#1a1a1a]">
|
||||
Timeline
|
||||
</span>
|
||||
<ArrowDownNarrowWide className="w-5 h-5 text-gray-500"/>
|
||||
@@ -29,7 +29,7 @@ export default function ProjectTimeline({ tasks }: { tasks: Task[] }) {
|
||||
<li key={idx} className="relative mb-6 list-none">
|
||||
{/* Dot */}
|
||||
<div
|
||||
className={`absolute -left-4 top-0.5 w-2.5 h-2.5 rounded-full border-2 border-white ${active ? 'bg-[#C0392B]' : 'bg-[#ccc]'
|
||||
className={`absolute -left-5 top-0.5 w-3 h-3 rounded-full border-2 border-white ${active ? 'bg-[#C0392B]' : 'bg-[#ccc]'
|
||||
} ${isToday ? 'shadow-md' : ''}`}
|
||||
/>
|
||||
<div
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState, useRef } from "react";
|
||||
import { FileText, UploadCloud, Trash2, X, FileUp } from "lucide-react";
|
||||
import { FileText, UploadCloud, X, FileUp } from "lucide-react";
|
||||
import { LuSendHorizontal } from "react-icons/lu";
|
||||
|
||||
interface TaskFormFileProps {
|
||||
|
||||
Reference in New Issue
Block a user