Files
internify-fe/src/services/NotificationService.ts
T
Kemas M. Aryadary Rasyad 62aaf2bcba feat: enhance project and mentor management features
- Updated MentorProjectCard to provide more detailed success/error messages upon archiving and completing projects.
- Adjusted layout for certificate generation to improve visual alignment.
- Introduced resolveErrorMessage utility to standardize error message handling across the application.
- Enhanced customToast functionality to handle hook failures more gracefully.
- Refactored useCertificates hook to return structured responses for certificate claims and generation.
- Updated useMentors hook to improve error handling and response structure for mentor operations.
- Improved useNotification hook to return structured responses for marking notifications as read.
- Refactored useProjects hook to provide structured responses for project creation, updates, and member assignments.
- Enhanced useTasks hook to return structured responses for task creation, updates, and deletions.
- Updated services to return structured responses with messages for various API calls related to certificates, mentors, notifications, projects, tasks, and user management.
- Moved mentor-related types to a dedicated user.types file for better organization.
2026-07-16 22:50:56 +07:00

101 lines
2.8 KiB
TypeScript

import api from "../lib/api";
import type { BackendNotification, UINotification } from "../types/notification.types";
export const getNotifications = async (): Promise<BackendNotification[]> => {
const res = await api.get("/notification-api");
return res.data.data;
};
export const markAllAsRead = async (): Promise<{ message: string }> => {
const res = await api.patch("/notification-api/read-all");
return { message: res.data.message };
};
export const markAsRead = async (
id: number
): Promise<{ data: BackendNotification; message: string }> => {
const res = await api.patch(`/notification-api/${id}/read`);
return { data: res.data.data, message: res.data.message };
};
export const mapType = (title: string): string => {
const t = title.toLowerCase();
if (t.includes("task") || t.includes("tugas")) return "new-task";
if (t.includes("certificate") || t.includes("sertifikat") || t.includes("achievement")) return "achievement";
return "system";
};
export const formatRelativeTime = (dateStr: string): string => {
try {
const date = new Date(dateStr);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffSec = Math.floor(diffMs / 1000);
const diffMin = Math.floor(diffSec / 60);
const diffHr = Math.floor(diffMin / 60);
const diffDays = Math.floor(diffHr / 24);
if (diffMs < 0 || diffSec < 5) {
return "Just now";
}
if (diffSec < 60) {
return `${diffSec} seconds ago`;
}
if (diffMin < 60) {
return `${diffMin} ${diffMin === 1 ? 'minute' : 'minutes'} ago`;
}
if (diffHr < 24) {
return `${diffHr} ${diffHr === 1 ? 'hour' : 'hours'} ago`;
}
if (diffDays === 1) {
return "Yesterday";
}
if (diffDays < 7) {
return `${diffDays} days ago`;
}
// Fallback to absolute date
return date.toLocaleDateString(undefined, {
month: 'short',
day: 'numeric',
year: 'numeric'
});
} catch (error) {
return "Some time ago";
}
};
export const mapGroup = (dateStr: string): "TODAY" | "YESTERDAY" => {
try {
const date = new Date(dateStr);
const now = new Date();
// Grouping: TODAY or YESTERDAY
// TODAY means today's calendar day
const isToday =
date.getDate() === now.getDate() &&
date.getMonth() === now.getMonth() &&
date.getFullYear() === now.getFullYear();
if (isToday) {
return "TODAY";
}
return "YESTERDAY";
} catch (e) {
return "YESTERDAY";
}
};
export const mapNotificationToUI = (notif: BackendNotification): UINotification => {
return {
id: notif.id,
type: mapType(notif.title),
title: notif.title,
time: formatRelativeTime(notif.created_at),
isNew: !notif.is_read,
link: notif.link ?? "",
group: mapGroup(notif.created_at),
description: notif.message,
};
};