fix: remove console log and improve notification handling in NotificationList
feat: enhance date formatting in MentorProjectDetailPage and add validation in CreateTaskDialog refactor: update status handling in StatusSubmissionTable and improve ProjectTaskCard styling fix: update toast icon for better clarity
This commit is contained in:
@@ -46,7 +46,6 @@ export default function InternifyLogin() {
|
|||||||
document.cookie = `token=${token}; path=/; SameSite=Strict`;
|
document.cookie = `token=${token}; path=/; SameSite=Strict`;
|
||||||
|
|
||||||
const decoded = decodeJWT(token);
|
const decoded = decodeJWT(token);
|
||||||
console.log(decoded)
|
|
||||||
const role = decoded?.role;
|
const role = decoded?.role;
|
||||||
if (role === "intern") {
|
if (role === "intern") {
|
||||||
navigate("/intern");
|
navigate("/intern");
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { Check, Download } from "lucide-react";
|
import { RiCheckDoubleLine } from "react-icons/ri";
|
||||||
|
import { Check } from "lucide-react";
|
||||||
import { LuFileSpreadsheet } from "react-icons/lu";
|
import { LuFileSpreadsheet } from "react-icons/lu";
|
||||||
|
import { MdOutlineEmail } from "react-icons/md";
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
import * as NotificationService from "../../services/NotificationService";
|
import * as NotificationService from "../../services/NotificationService";
|
||||||
import type { UINotification, BackendNotification } from "../../types/notification.types";
|
import type { UINotification, BackendNotification } from "../../types/notification.types";
|
||||||
@@ -22,8 +24,9 @@ export default function NotificationList() {
|
|||||||
const loadNotifications = async () => {
|
const loadNotifications = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await NotificationService.getNotifications();
|
const data = await NotificationService.getNotifications();
|
||||||
const unread = data.filter((n) => !n.is_read);
|
// const unread = data.filter((n) => !n.is_read);
|
||||||
const mapped = unread.map(NotificationService.mapNotificationToUI);
|
// const mapped = unread.map(NotificationService.mapNotificationToUI);
|
||||||
|
const mapped = data.map(NotificationService.mapNotificationToUI);
|
||||||
setNotifications(mapped);
|
setNotifications(mapped);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to load notifications:", err);
|
console.error("Failed to load notifications:", err);
|
||||||
@@ -35,7 +38,7 @@ export default function NotificationList() {
|
|||||||
const token = getCookieToken();
|
const token = getCookieToken();
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|
||||||
const socketUrl = import.meta.env.VITE_API_BASE_URL || "http://localhost:9000";
|
const socketUrl = import.meta.env.VITE_API_BASE_URL;
|
||||||
const socket = io(socketUrl, {
|
const socket = io(socketUrl, {
|
||||||
auth: { token },
|
auth: { token },
|
||||||
transports: ["websocket"]
|
transports: ["websocket"]
|
||||||
@@ -47,7 +50,6 @@ export default function NotificationList() {
|
|||||||
|
|
||||||
socket.on("notification", (notif: BackendNotification) => {
|
socket.on("notification", (notif: BackendNotification) => {
|
||||||
console.log("New realtime notification received:", notif);
|
console.log("New realtime notification received:", notif);
|
||||||
if (notif.is_read) return;
|
|
||||||
const mapped = NotificationService.mapNotificationToUI(notif);
|
const mapped = NotificationService.mapNotificationToUI(notif);
|
||||||
setNotifications(prev => {
|
setNotifications(prev => {
|
||||||
if (prev.some(p => p.id === mapped.id)) {
|
if (prev.some(p => p.id === mapped.id)) {
|
||||||
@@ -69,7 +71,7 @@ export default function NotificationList() {
|
|||||||
const handleMarkAllRead = async () => {
|
const handleMarkAllRead = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await NotificationService.markAllAsRead();
|
const res = await NotificationService.markAllAsRead();
|
||||||
setNotifications([]);
|
setNotifications(prev => prev.map(n => ({ ...n, isNew: false })));
|
||||||
customToast.success("Berhasil", res.message);
|
customToast.success("Berhasil", res.message);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const msg = err?.response?.data?.message ?? "Gagal menandai semua notifikasi.";
|
const msg = err?.response?.data?.message ?? "Gagal menandai semua notifikasi.";
|
||||||
@@ -80,7 +82,9 @@ export default function NotificationList() {
|
|||||||
const handleReadMessage = async (id: number) => {
|
const handleReadMessage = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
const res = await NotificationService.markAsRead(id);
|
const res = await NotificationService.markAsRead(id);
|
||||||
setNotifications(prev => prev.filter(n => n.id !== id));
|
setNotifications(prev =>
|
||||||
|
prev.map(n => (n.id === id ? { ...n, isNew: false } : n))
|
||||||
|
);
|
||||||
customToast.success("Ditandai dibaca", res.message);
|
customToast.success("Ditandai dibaca", res.message);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const msg = err?.response?.data?.message ?? "Gagal menandai notifikasi.";
|
const msg = err?.response?.data?.message ?? "Gagal menandai notifikasi.";
|
||||||
@@ -100,9 +104,9 @@ export default function NotificationList() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleMarkAllRead}
|
onClick={handleMarkAllRead}
|
||||||
className="flex items-center gap-1.5 self-start sm:self-center px-4 py-2 border border-gray-200 rounded-lg text-xs font-semibold text-gray-700 bg-white hover:bg-gray-50 transition-colors shadow-sm"
|
className="flex items-center gap-1.5 self-start sm:self-center px-4 py-2 border border-gray-100 rounded-lg text-xs font-semibold text-red bg-white hover:bg-gray-50 transition-colors shadow-sm"
|
||||||
>
|
>
|
||||||
<Check className="w-4 h-4 text-green-600 stroke-[3]" />
|
<RiCheckDoubleLine className="w-4 h-4 text-red stroke-[3]" />
|
||||||
Mark all as read
|
Mark all as read
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,72 +119,136 @@ export default function NotificationList() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
{/* SECTION TODAY */}
|
||||||
{/* Render Group TODAY */}
|
{notifications.filter((n) => n.group === "TODAY").length > 0 && (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{notifications.filter(n => n.group === "TODAY").map((item) => (
|
{notifications
|
||||||
<div
|
.filter((n) => n.group === "TODAY")
|
||||||
key={item.id}
|
.map((item) => (
|
||||||
className={`relative flex items-start gap-4 p-5 bg-box border border-card-outline/40 rounded-xl shadow-[0_2px_10px_rgba(0,0,0,0.01)] ${item.type === 'new-task' ? 'border-l-4 border-l-[#B30000]' : ''
|
<div
|
||||||
}`}
|
key={item.id}
|
||||||
>
|
className={`relative flex items-start gap-4 p-5 bg-white border border-gray-200/80 rounded-xl shadow-sm ${item.isNew ? "border-l-4 border-l-[#B30000]" : ""
|
||||||
{/* Icon Container */}
|
}`}
|
||||||
<div className={`p-2.5 rounded-xl ${item.type === 'new-task' ? 'bg-red-50 text-red-600' : 'bg-gray-100 text-gray-600'
|
>
|
||||||
}`}>
|
{/* Icon Container */}
|
||||||
{item.type === 'new-task' && <LuFileSpreadsheet className="w-5 h-5" />}
|
<div
|
||||||
{item.type === 'achievement' && <Check className="w-5 h-5 stroke-[2.5]" />}
|
className={`p-2.5 rounded-xl ${item.isNew
|
||||||
</div>
|
? "bg-red-100 text-red-600"
|
||||||
|
: "bg-gray-100 text-gray-600"
|
||||||
{/* Content text */}
|
}`}
|
||||||
<div className="flex-grow space-y-1">
|
>
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
{item.type === "new-task" ? (
|
||||||
{item.isNew && (
|
<LuFileSpreadsheet className="w-5 h-5" />
|
||||||
<span className="bg-[#B30000] text-white font-extrabold text-[9px] px-2 py-0.5 rounded uppercase tracking-wider">
|
) : item.type === "achievement" ? (
|
||||||
NEW
|
<Check className="w-5 h-5 stroke-[2.5]" />
|
||||||
</span>
|
) : (
|
||||||
)}
|
<MdOutlineEmail className="w-5 h-5" />
|
||||||
<h3 className="text-sm font-bold text-gray-900">{item.title}</h3>
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Custom description coloring logic */}
|
|
||||||
<p className="text-xs text-gray-500 font-medium leading-relaxed max-w-2xl">
|
|
||||||
{item.description}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* Conditional Actions */}
|
|
||||||
{item.type === 'new-task' && item.link && (
|
|
||||||
<div className="flex items-center gap-2 pt-3">
|
|
||||||
<button
|
|
||||||
className="px-4 py-1.5 bg-[#B30000] hover:bg-[#990000] text-white text-xs font-bold rounded-lg shadow-sm transition-colors"
|
|
||||||
onClick={() => navigate(`${item.link}`)}>
|
|
||||||
View Task
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-1.5 border border-card-outline text-font hover:text-font-shade hover:bg-gray-50 text-xs font-semibold rounded-lg transition-colors"
|
|
||||||
onClick={() => handleReadMessage(item.id)}
|
|
||||||
>
|
|
||||||
Later
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
{item.type === 'achievement' && (
|
{/* Content Text */}
|
||||||
<button
|
<div className="flex-grow space-y-1">
|
||||||
className="flex items-center gap-1 text-xs font-bold text-[#B30000] hover:underline pt-2"
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
onClick={() => navigate(`/certificates`)}>
|
{item.isNew && (
|
||||||
<Download className="w-3.5 h-3.5" />
|
<span className="bg-[#B30000] text-white font-extrabold text-[9px] px-2 py-0.5 rounded uppercase tracking-wider">
|
||||||
Ke Halaman
|
NEW
|
||||||
</button>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
<h3 className="text-sm font-bold text-gray-900">
|
||||||
|
{item.title}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Time */}
|
<p className="text-xs text-gray-500 font-medium leading-relaxed max-w-2xl">
|
||||||
<span className="text-[11px] text-gray-400 font-medium whitespace-nowrap self-start md:absolute md:top-5 md:right-5">
|
{item.description}
|
||||||
{item.time}
|
</p>
|
||||||
</span>
|
|
||||||
</div>
|
{/* Actions */}
|
||||||
))}
|
<div className="flex items-center gap-2 pt-3">
|
||||||
</div>
|
{item.link && (
|
||||||
|
<button
|
||||||
|
className="px-4 py-1.5 bg-[#B30000] hover:bg-[#990000] text-white text-xs font-bold rounded-lg shadow-sm transition-colors"
|
||||||
|
onClick={() => navigate(`${item.link}`)}
|
||||||
|
>
|
||||||
|
View Task
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{item.isNew && (
|
||||||
|
<button
|
||||||
|
className="px-4 py-1.5 border border-gray-200 text-gray-600 hover:bg-gray-50 text-xs font-semibold rounded-lg transition-colors"
|
||||||
|
onClick={() => handleReadMessage(item.id)}
|
||||||
|
>
|
||||||
|
Later
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Time */}
|
||||||
|
<span className="text-[11px] text-gray-400 font-medium whitespace-nowrap self-start md:absolute md:top-5 md:right-5">
|
||||||
|
{item.time}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* SECTION YESTERDAY / SEBELUMNYA */}
|
||||||
|
{notifications.filter((n) => n.group !== "TODAY").length > 0 && (
|
||||||
|
<div className="space-y-3 pt-4">
|
||||||
|
{/* Subheader Title */}
|
||||||
|
<h2 className="text-xs font-bold text-gray-400 tracking-wider uppercase">
|
||||||
|
YESTERDAY
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{notifications
|
||||||
|
.filter((n) => n.group !== "TODAY")
|
||||||
|
.map((item) => (
|
||||||
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className="relative flex items-start gap-4 p-5 bg-gray-100/70 border border-gray-200/50 rounded-xl"
|
||||||
|
>
|
||||||
|
{/* Icon Container Gray */}
|
||||||
|
<div className="p-2.5 rounded-xl bg-gray-200/60 text-gray-500">
|
||||||
|
{item.type === "new-task" ? (
|
||||||
|
<LuFileSpreadsheet className="w-5 h-5" />
|
||||||
|
) : item.type === "achievement" ? (
|
||||||
|
<Check className="w-5 h-5 stroke-[2.5]" />
|
||||||
|
) : (
|
||||||
|
<MdOutlineEmail className="w-5 h-5" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content Text */}
|
||||||
|
<div className="flex-grow space-y-1">
|
||||||
|
<h3 className="text-sm font-bold text-gray-700">
|
||||||
|
{item.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-xs text-gray-500 font-medium leading-relaxed max-w-2xl">
|
||||||
|
{item.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Action Button untuk Yesterday jika ada */}
|
||||||
|
{item.link && (
|
||||||
|
<div className="pt-2">
|
||||||
|
<button
|
||||||
|
className="text-xs font-bold text-[#B30000] hover:underline flex items-center gap-1"
|
||||||
|
onClick={() => navigate(`${item.link}`)}
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Time */}
|
||||||
|
<span className="text-[11px] text-gray-400 font-medium whitespace-nowrap self-start md:absolute md:top-5 md:right-5">
|
||||||
|
{item.time}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -53,12 +53,10 @@ export default function TaskCard({ task }: { task: InternTaskItem }) {
|
|||||||
Tipe Submission : {task.submission_type === 'file_upload' ? "File" : "Link"}
|
Tipe Submission : {task.submission_type === 'file_upload' ? "File" : "Link"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`shrink-0 hidden md:flex items-center rounded-xl border ${statusStyles[displayStatus]}`}>
|
||||||
|
|
||||||
<div className="shrink-0 hidden md:flex items-center border border-card-outline">
|
|
||||||
<span
|
<span
|
||||||
className={`font-semibold text-xs px-3.5 py-[5px] rounded-md whitespace-nowrap border ${statusStyles[displayStatus]}`}>
|
className={`font-semibold text-xs px-3.5 py-[5px] whitespace-nowrap`}>
|
||||||
{statusLabels[task.submission_status]}
|
{statusLabels[displayStatus]}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -118,7 +118,11 @@ export default function MentorProjectsDetailPage() {
|
|||||||
{/* Kolom Tanggal Kumpul */}
|
{/* Kolom Tanggal Kumpul */}
|
||||||
<td className="px-6 py-4 text-sm text-gray-500">
|
<td className="px-6 py-4 text-sm text-gray-500">
|
||||||
{sub.submitted_at
|
{sub.submitted_at
|
||||||
? new Date(sub.submitted_at).toLocaleDateString("id-ID")
|
? new Date(sub.submitted_at).toLocaleString("id-ID", {
|
||||||
|
day: "numeric",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
})
|
||||||
: "-"}
|
: "-"}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@@ -126,12 +130,12 @@ export default function MentorProjectsDetailPage() {
|
|||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
{sub.display_status === "done" && (
|
{sub.display_status === "done" && (
|
||||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 text-xs font-semibold rounded-full bg-green-50 text-green-700 border border-green-200">
|
<span className="inline-flex items-center gap-1.5 px-3 py-1 text-xs font-semibold rounded-full bg-green-50 text-green-700 border border-green-200">
|
||||||
<span className="w-1.5 h-1.5 bg-green-500 rounded-full"></span> Done
|
<span className="w-1.5 h-1.5 bg-green-700 rounded-full"></span> Done
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{sub.display_status === "pending" && (
|
{sub.display_status === "pending" && (
|
||||||
<span className="inline-flex items-center gap-1.5 px-3 py-1 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 border border-amber-200">
|
<span className="inline-flex items-center gap-1.5 px-3 py-1 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 border border-amber-200">
|
||||||
<span className="w-1.5 h-1.5 bg-amber-500 rounded-full"></span> Pending
|
<span className="w-1.5 h-1.5 bg-amber-700 rounded-full"></span> Pending
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{sub.display_status === "overdue" && (
|
{sub.display_status === "overdue" && (
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export default function CreateTaskModal({ isOpen, onClose, projectId, onSuccess
|
|||||||
const [taskTitle, setTaskTitle] = useState("");
|
const [taskTitle, setTaskTitle] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
const [deadlineDate, setDeadlineDate] = useState("");
|
const [deadlineDate, setDeadlineDate] = useState("");
|
||||||
|
const [dateError, setDateError] = useState("");
|
||||||
const [specificTime, setSpecificTime] = useState("");
|
const [specificTime, setSpecificTime] = useState("");
|
||||||
const [submissionType, setSubmissionType] = useState<SubmissionType>("file_upload");
|
const [submissionType, setSubmissionType] = useState<SubmissionType>("file_upload");
|
||||||
|
|
||||||
@@ -50,6 +51,17 @@ export default function CreateTaskModal({ isOpen, onClose, projectId, onSuccess
|
|||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
setDateError("");
|
||||||
|
|
||||||
|
if (deadlineDate) {
|
||||||
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
if (deadlineDate < today) {
|
||||||
|
setDateError("Deadline date cannot be in the past");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const result = await create({
|
const result = await create({
|
||||||
title: taskTitle,
|
title: taskTitle,
|
||||||
description,
|
description,
|
||||||
@@ -104,8 +116,11 @@ export default function CreateTaskModal({ isOpen, onClose, projectId, onSuccess
|
|||||||
type="date"
|
type="date"
|
||||||
required
|
required
|
||||||
value={deadlineDate}
|
value={deadlineDate}
|
||||||
onChange={(e) => setDeadlineDate(e.target.value)}
|
onChange={(e) => { setDeadlineDate(e.target.value); setDateError(""); }}
|
||||||
className="w-full px-3 py-3 bg-white border border-gray-200 rounded-lg text-xs font-medium text-gray-800 focus:outline-none focus:border-[#B30000] focus:ring-1 focus:ring-[#B30000]" />
|
className="w-full px-3 py-3 bg-white border border-gray-200 rounded-lg text-xs font-medium text-gray-800 focus:outline-none focus:border-[#B30000] focus:ring-1 focus:ring-[#B30000]" />
|
||||||
|
{dateError && (
|
||||||
|
<p className="text-xs text-red font-medium">{dateError}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<label className="text-xs font-bold text-gray-700 tracking-wide">Specific Time</label>
|
<label className="text-xs font-bold text-gray-700 tracking-wide">Specific Time</label>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ interface StatusTableProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function StatusTable({ status, submission }: StatusTableProps) {
|
export function StatusTable({ status, submission }: StatusTableProps) {
|
||||||
const hasSubmission = status === "submitted" || status === "done";
|
const hasSubmission = status === "submitted" || status == "overdue";
|
||||||
|
|
||||||
const rows: { label: string; value: React.ReactNode }[] = [
|
const rows: { label: string; value: React.ReactNode }[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import toast, { type Toast } from 'react-hot-toast';
|
import toast, { type Toast } from 'react-hot-toast';
|
||||||
import { FiX } from 'react-icons/fi';
|
import { FiX } from 'react-icons/fi';
|
||||||
import { FaCheck } from "react-icons/fa";
|
import { FaCheck } from "react-icons/fa";
|
||||||
import { IoAlertOutline } from "react-icons/io5";
|
import { IoAlertCircleOutline } from "react-icons/io5";
|
||||||
|
|
||||||
function ToastCard({ t, type, title, description }: {
|
function ToastCard({ t, type, title, description }: {
|
||||||
t: Toast;
|
t: Toast;
|
||||||
@@ -19,7 +19,7 @@ function ToastCard({ t, type, title, description }: {
|
|||||||
>
|
>
|
||||||
<div className={`flex items-center justify-center w-6 h-6 rounded-full mt-0.5 shrink-0
|
<div className={`flex items-center justify-center w-6 h-6 rounded-full mt-0.5 shrink-0
|
||||||
${isSuccess ? 'bg-green-600 text-white' : 'bg-red-600 text-white'}`}>
|
${isSuccess ? 'bg-green-600 text-white' : 'bg-red-600 text-white'}`}>
|
||||||
{isSuccess ? <FaCheck size={10} /> : <IoAlertOutline size={10} />}
|
{isSuccess ? <FaCheck size={10} /> : <IoAlertCircleOutline size={10} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<p className={`font-semibold text-[10px] ${isSuccess ? 'text-green-700' : 'text-red-700'}`}>
|
<p className={`font-semibold text-[10px] ${isSuccess ? 'text-green-700' : 'text-red-700'}`}>
|
||||||
|
|||||||
Reference in New Issue
Block a user