feat: implement core admin dashboard infrastructure including service layers, UI components, and submission management pages
This commit is contained in:
@@ -31,7 +31,7 @@ export default function Profile() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] lg:p-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/3 lg:p-6">
|
||||
<h3 className="mb-5 text-lg font-semibold text-gray-800 dark:text-white/90 lg:mb-7">
|
||||
Profile
|
||||
</h3>
|
||||
|
||||
@@ -11,7 +11,7 @@ export default function BlankPage() {
|
||||
return (
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Blank Page" />
|
||||
<div className="min-h-screen rounded-2xl border border-gray-200 bg-white px-5 py-7 dark:border-gray-800 dark:bg-white/[0.03] xl:px-10 xl:py-12">
|
||||
<div className="min-h-screen rounded-2xl border border-gray-200 bg-white px-5 py-7 dark:border-gray-800 dark:bg-white/3 xl:px-10 xl:py-12">
|
||||
<div className="mx-auto w-full max-w-[630px] text-center">
|
||||
<h3 className="mb-4 font-semibold text-gray-800 text-theme-xl dark:text-white/90 sm:text-2xl">
|
||||
Card Title Here
|
||||
|
||||
@@ -240,7 +240,6 @@ export default function Page() {
|
||||
} else {
|
||||
toast.error("Lỗi hệ thống khi cập nhật");
|
||||
}
|
||||
console.error(error);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function BadgePage() {
|
||||
<div>
|
||||
<PageBreadcrumb pageTitle="Badges" />
|
||||
<div className="space-y-5 sm:space-y-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
With Light Background
|
||||
@@ -50,7 +50,7 @@ export default function BadgePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
With Solid Background
|
||||
@@ -84,7 +84,7 @@ export default function BadgePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Light Background with Left Icon
|
||||
@@ -117,7 +117,7 @@ export default function BadgePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Solid Background with Left Icon
|
||||
@@ -150,7 +150,7 @@ export default function BadgePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Light Background with Right Icon
|
||||
@@ -183,7 +183,7 @@ export default function BadgePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="px-6 py-5">
|
||||
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
|
||||
Solid Background with Right Icon
|
||||
|
||||
+1
-1
@@ -554,7 +554,7 @@ span.flatpickr-weekday,
|
||||
@apply p-2;
|
||||
}
|
||||
.fc .fc-daygrid-day.fc-day-today .fc-scrollgrid-sync-inner {
|
||||
@apply rounded-sm bg-gray-100 dark:bg-white/[0.03];
|
||||
@apply rounded-sm bg-gray-100 dark:bg-white/3;
|
||||
}
|
||||
.fc .fc-daygrid-day-number {
|
||||
@apply !p-3 text-sm font-medium text-gray-700 dark:text-gray-400;
|
||||
|
||||
@@ -121,7 +121,7 @@ const Calendar: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="custom-calendar">
|
||||
<FullCalendar
|
||||
ref={calendarRef}
|
||||
@@ -201,8 +201,7 @@ const Calendar: React.FC = () => {
|
||||
/>
|
||||
<span className="flex items-center justify-center w-5 h-5 mr-2 border border-gray-300 rounded-full box dark:border-gray-700">
|
||||
<span
|
||||
className={`h-2 w-2 rounded-full bg-white ${
|
||||
eventLevel === key ? "block" : "hidden"
|
||||
className={`h-2 w-2 rounded-full bg-white ${eventLevel === key ? "block" : "hidden"
|
||||
}`}
|
||||
></span>
|
||||
</span>
|
||||
|
||||
@@ -17,7 +17,7 @@ const ComponentCard: React.FC<ComponentCardProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03] ${className}`}
|
||||
className={`rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3 ${className}`}
|
||||
>
|
||||
{/* Card Header */}
|
||||
<div className="px-6 py-5 flex items-center justify-between">
|
||||
|
||||
@@ -133,7 +133,7 @@ export default function MonthlyNewChart() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-5 pt-5 dark:border-gray-800 dark:bg-white/[0.03] sm:px-6 sm:pt-6">
|
||||
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-5 pt-5 dark:border-gray-800 dark:bg-white/3 sm:px-6 sm:pt-6">
|
||||
<div className="flex flex-col gap-4 mb-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
Lượng tạo mới hàng tháng
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function DemographicCard() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] sm:p-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/3 sm:p-6">
|
||||
<div className="flex justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
|
||||
@@ -52,7 +52,7 @@ export default function DetailedStatsTable() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] md:p-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/3 md:p-6">
|
||||
<h3 className="mb-4 text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
Bảng Số Liệu Chi Tiết (Hôm nay vs Hôm qua)
|
||||
</h3>
|
||||
|
||||
@@ -47,8 +47,7 @@ export const EcommerceMetrics = () => {
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-6">
|
||||
{/* <!-- Metric Item Start --> */}
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] md:p-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/3 md:p-6">
|
||||
<div className="flex items-center justify-center w-12 h-12 bg-gray-100 rounded-xl dark:bg-gray-800">
|
||||
<GroupIcon className="text-gray-800 size-6 dark:text-white/90" />
|
||||
</div>
|
||||
@@ -68,10 +67,8 @@ export const EcommerceMetrics = () => {
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!-- Metric Item End --> */}
|
||||
|
||||
{/* <!-- Metric Item Start --> */}
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/[0.03] md:p-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-5 dark:border-gray-800 dark:bg-white/3 md:p-6">
|
||||
<div className="flex items-center justify-center w-12 h-12 bg-gray-100 rounded-xl dark:bg-gray-800">
|
||||
<BoxIconLine className="text-gray-800 dark:text-white/90" />
|
||||
</div>
|
||||
@@ -91,7 +88,6 @@ export const EcommerceMetrics = () => {
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!-- Metric Item End --> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -108,7 +108,7 @@ export default function MonthlySalesChart() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-5 pt-5 dark:border-gray-800 dark:bg-white/[0.03] sm:px-6 sm:pt-6">
|
||||
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-5 pt-5 dark:border-gray-800 dark:bg-white/3 sm:px-6 sm:pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
Monthly Sales
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function MonthlyTarget() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-gray-200 bg-gray-100 dark:border-gray-800 dark:bg-white/[0.03]">
|
||||
<div className="rounded-2xl border border-gray-200 bg-gray-100 dark:border-gray-800 dark:bg-white/3">
|
||||
<div className="px-5 pt-5 bg-white shadow-default rounded-2xl pb-11 dark:bg-gray-900 sm:px-6 sm:pt-6">
|
||||
<div className="flex justify-between">
|
||||
<div>
|
||||
|
||||
@@ -71,7 +71,7 @@ const tableData: Product[] = [
|
||||
|
||||
export default function RecentOrders() {
|
||||
return (
|
||||
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-4 pb-3 pt-4 dark:border-gray-800 dark:bg-white/[0.03] sm:px-6">
|
||||
<div className="overflow-hidden rounded-2xl border border-gray-200 bg-white px-4 pb-3 pt-4 dark:border-gray-800 dark:bg-white/3 sm:px-6">
|
||||
<div className="flex flex-col gap-2 mb-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function StatisticsChart() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-gray-200 bg-white px-5 pb-5 pt-5 dark:border-gray-800 dark:bg-white/[0.03] sm:px-6 sm:pt-6">
|
||||
<div className="rounded-2xl border border-gray-200 bg-white px-5 pb-5 pt-5 dark:border-gray-800 dark:bg-white/3 sm:px-6 sm:pt-6">
|
||||
<div className="flex flex-col gap-5 mb-6 sm:flex-row sm:justify-between">
|
||||
<div className="w-full">
|
||||
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
|
||||
|
||||
@@ -147,7 +147,7 @@ export default function ApplicationTable({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-white/[0.05] dark:bg-white/[0.03]">
|
||||
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-white/[0.05] dark:bg-white/3">
|
||||
<div className="max-w-full overflow-x-auto">
|
||||
<div className="min-w-[1000px]">
|
||||
<Table>
|
||||
|
||||
@@ -84,7 +84,7 @@ export default function BasicTableOne({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-white/[0.05] dark:bg-white/[0.03]">
|
||||
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-white/[0.05] dark:bg-white/3">
|
||||
<div className="max-w-full overflow-x-auto">
|
||||
<div className="min-w-[1100px]">
|
||||
<Table>
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function MediaTable({
|
||||
const isAllSelected = data.length > 0 && selectedIds.length === data.length;
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-white/[0.05] dark:bg-white/[0.03]">
|
||||
<div className="overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-white/[0.05] dark:bg-white/3">
|
||||
<div className="max-w-full overflow-x-auto">
|
||||
<div className="min-w-[1000px]">
|
||||
<Table>
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import axios from "axios";
|
||||
import { API } from "../../api";
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: "/",
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.response.use(
|
||||
(response) => {
|
||||
if (response.data && response.data.status === false) {
|
||||
return handleRefreshToken(response);
|
||||
}
|
||||
return response;
|
||||
},
|
||||
async (error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
async function handleRefreshToken(originalResponse: any) {
|
||||
try {
|
||||
const refreshRes = await axios.get(API.Auth.REFRESH, { withCredentials: true });
|
||||
|
||||
if (refreshRes.data && refreshRes.data.status !== false) {
|
||||
return axiosInstance(originalResponse.config);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Refresh token failed", err);
|
||||
}
|
||||
return originalResponse;
|
||||
}
|
||||
|
||||
export default axiosInstance;
|
||||
+61
-38
@@ -1,65 +1,88 @@
|
||||
import axios from "axios"
|
||||
import { API_URL_ROOT } from "../../api"
|
||||
import axios, { AxiosError, InternalAxiosRequestConfig } from "axios";
|
||||
|
||||
const baseURL = API_URL_ROOT || "https://history-api.kain.id.vn"
|
||||
export const baseURL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3344";
|
||||
|
||||
const api = axios.create({
|
||||
export const api = axios.create({
|
||||
baseURL,
|
||||
withCredentials: true
|
||||
})
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
let isRefreshing = false
|
||||
let queue: any[] = []
|
||||
|
||||
const processQueue = (error?: any) => {
|
||||
queue.forEach((p) => {
|
||||
if (error) p.reject(error)
|
||||
else p.resolve()
|
||||
})
|
||||
queue = []
|
||||
interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
|
||||
_retry?: boolean;
|
||||
}
|
||||
|
||||
interface QueueItem {
|
||||
resolve: () => void;
|
||||
reject: (error: unknown) => void;
|
||||
}
|
||||
|
||||
let isRefreshing = false;
|
||||
let queue: QueueItem[] = [];
|
||||
|
||||
const processQueue = (error: unknown = null) => {
|
||||
queue.forEach((p) => {
|
||||
if (error) p.reject(error);
|
||||
else p.resolve();
|
||||
});
|
||||
queue = [];
|
||||
};
|
||||
|
||||
const skipRefreshUrls = [
|
||||
"/auth/signin",
|
||||
"/auth/signup",
|
||||
"/auth/logout",
|
||||
"/auth/refresh",
|
||||
"/auth/forgot-password",
|
||||
"/auth/token/create",
|
||||
"/auth/token/verify",
|
||||
];
|
||||
|
||||
api.interceptors.response.use(
|
||||
(res) => res,
|
||||
async (err) => {
|
||||
const originalRequest = err.config
|
||||
async (err: AxiosError) => {
|
||||
const originalRequest = err.config as CustomAxiosRequestConfig;
|
||||
|
||||
if (err.response?.status === 401 && !originalRequest._retry) {
|
||||
const url = originalRequest?.url || "";
|
||||
|
||||
const shouldSkip = skipRefreshUrls?.some((path) =>
|
||||
url?.includes(path)
|
||||
);
|
||||
|
||||
if (
|
||||
err.response?.status === 401 &&
|
||||
originalRequest &&
|
||||
!originalRequest._retry &&
|
||||
!shouldSkip
|
||||
) {
|
||||
if (isRefreshing) {
|
||||
return new Promise((resolve, reject) => {
|
||||
queue.push({
|
||||
resolve: () => resolve(api(originalRequest)),
|
||||
reject
|
||||
})
|
||||
})
|
||||
reject: (queueErr) => reject(queueErr),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
originalRequest._retry = true
|
||||
isRefreshing = true
|
||||
originalRequest._retry = true;
|
||||
isRefreshing = true;
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
`${baseURL}/auth/refresh`,
|
||||
{},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
await axios.post(`${baseURL}/auth/refresh`, {}, { withCredentials: true });
|
||||
|
||||
processQueue()
|
||||
processQueue(null);
|
||||
|
||||
return api(originalRequest)
|
||||
return api(originalRequest);
|
||||
} catch (refreshErr) {
|
||||
processQueue(refreshErr)
|
||||
processQueue(refreshErr);
|
||||
|
||||
window.location.href = "/signin"
|
||||
window.location.href = "/auth/signin"
|
||||
|
||||
return Promise.reject(refreshErr)
|
||||
return Promise.reject(refreshErr);
|
||||
} finally {
|
||||
isRefreshing = false
|
||||
isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(err)
|
||||
return Promise.reject(err);
|
||||
}
|
||||
)
|
||||
|
||||
export default api
|
||||
);
|
||||
|
||||
+11
-4
@@ -1,8 +1,15 @@
|
||||
export interface CommonResponse<T = any> {
|
||||
export interface ErrorResponse {
|
||||
failed_field: string;
|
||||
tag: string;
|
||||
value: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface CommonResponse<T = unknown> {
|
||||
status: boolean;
|
||||
message: string;
|
||||
data: T;
|
||||
errors?: any; // Or a more specific error type
|
||||
errors?: ErrorResponse[]; // Or a more specific error type
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
@@ -15,7 +22,7 @@ export interface PaginatedResponse<T> {
|
||||
total_records: number;
|
||||
total_pages: number;
|
||||
};
|
||||
errors?: any;
|
||||
errors?: ErrorResponse[];
|
||||
}
|
||||
|
||||
export interface CursorPaginatedResponse<T> {
|
||||
@@ -25,5 +32,5 @@ export interface CursorPaginatedResponse<T> {
|
||||
items: T[];
|
||||
next_cursor_id?: string;
|
||||
};
|
||||
errors?: any;
|
||||
errors?: ErrorResponse[];
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export interface ApplicationDto {
|
||||
reviewed_at: string | null;
|
||||
created_at: string;
|
||||
updated_at?: string;
|
||||
media: any[];
|
||||
media: MediaDto[];
|
||||
user: {
|
||||
display_name?: string;
|
||||
avatar_url?: string;
|
||||
|
||||
+41
-19
@@ -1,22 +1,46 @@
|
||||
export interface Project {
|
||||
export interface CommitSimpleResponse {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
project_status: "PRIVATE" | "PUBLIC" | "ARCHIVE";
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
is_deleted?: boolean;
|
||||
user_id?: string;
|
||||
user?: {
|
||||
edit_summary: string;
|
||||
}
|
||||
|
||||
export interface MemberSimpleResponse {
|
||||
user_id: string;
|
||||
role: string;
|
||||
display_name: string;
|
||||
avatar_url: string;
|
||||
}
|
||||
|
||||
export interface SubmissionSimpleResponse {
|
||||
id: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface UserSimpleResponse {
|
||||
id: string;
|
||||
email: string;
|
||||
display_name: string;
|
||||
avatar_url: string;
|
||||
};
|
||||
commits?: any[];
|
||||
submission_ids?: any[];
|
||||
members?: ProjectMember[];
|
||||
}
|
||||
|
||||
export interface Project {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
latest_commit_id?: string | null;
|
||||
project_status: "PRIVATE" | "PUBLIC" | "ARCHIVE" | string;
|
||||
locked_by?: string | null;
|
||||
is_deleted: boolean;
|
||||
user_id: string;
|
||||
created_at?: string | null;
|
||||
updated_at?: string | null;
|
||||
|
||||
user?: UserSimpleResponse | null;
|
||||
|
||||
commits: CommitSimpleResponse[];
|
||||
submissions: SubmissionSimpleResponse[];
|
||||
members: MemberSimpleResponse[];
|
||||
}
|
||||
|
||||
export interface ProjectsResponse<T = Project> {
|
||||
status: boolean;
|
||||
message: string;
|
||||
@@ -28,24 +52,22 @@ export interface ProjectsResponse<T = Project> {
|
||||
total_pages: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface UpdateProjectPayload {
|
||||
title: string;
|
||||
description: string;
|
||||
status: "PRIVATE" | "PUBLIC" | "ARCHIVE";
|
||||
}
|
||||
|
||||
export interface ChangeOwnerPayload {
|
||||
new_owner_id: string;
|
||||
}
|
||||
|
||||
export interface ProjectMemberPayload {
|
||||
user_id?: string;
|
||||
role: "EDITOR" | "VIEWER" | "ADMIN";
|
||||
}
|
||||
export interface ProjectMember {
|
||||
user_id: string;
|
||||
role: string;
|
||||
display_name: string;
|
||||
avatar_url: string;
|
||||
}
|
||||
|
||||
export interface GetProjectsParams {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
|
||||
@@ -4,7 +4,7 @@ export default function SidebarWidget() {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
mx-auto mb-10 w-full max-w-60 rounded-2xl bg-gray-50 px-4 py-5 text-center dark:bg-white/[0.03]`}
|
||||
mx-auto mb-10 w-full max-w-60 rounded-2xl bg-gray-50 px-4 py-5 text-center dark:bg-white/3`}
|
||||
>
|
||||
<h3 className="mb-2 font-semibold text-gray-900 dark:text-white">
|
||||
#1 Tailwind CSS Dashboard
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
import { getUserDto } from "@/interface/admin";
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
|
||||
export const apiCreateOTP = async (email: string) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
|
||||
export const createHistorianCV = async (payload: any) => {
|
||||
@@ -6,7 +6,7 @@ export const createHistorianCV = async (payload: any) => {
|
||||
return response?.data;
|
||||
};
|
||||
|
||||
export const apiGetUserApplications = async (payload :any) => {
|
||||
export const apiGetUserApplications = async (payload: any) => {
|
||||
const response = await api.get(API.Historian.APPLICATION, { params: payload });
|
||||
return response?.data;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
import { payloadPresignedMedia } from "@/interface/media";
|
||||
import axios from "axios";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
import { ProjectMemberPayload, ChangeOwnerPayload, CreateCommitPayload, GetProjectsParams, Project, RestoreCommitPayload, UpdateProjectPayload } from "@/interface/project";
|
||||
import { CommonResponse, CursorPaginatedResponse, PaginatedResponse } from "@/interface/common";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
import { GetStatisticsParams, StatisticResponse } from "@/interface/statistics";
|
||||
import { CommonResponse } from "@/interface/common";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
import { getSubmissionPayload, updateSubmissionPayload } from "@/interface/submission";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from "@/config/config";
|
||||
import { api } from "@/config/config";
|
||||
import { API } from "../../api";
|
||||
import { Profile } from "@/interface/user";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user