first commit
This commit is contained in:
73
frontend/app/utils/api/apiRequests/baseApiRequest.ts
Normal file
73
frontend/app/utils/api/apiRequests/baseApiRequest.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
"use server";
|
||||
|
||||
import { getValidAccessToken } from "ikoncomponents";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export interface ExtraOptionsProps {
|
||||
isAccessTokenRequird?: boolean;
|
||||
revalidatePaths?: string[];
|
||||
isReturnErrorResult?: boolean;
|
||||
}
|
||||
|
||||
export const baseApiRequest = async (
|
||||
url: string,
|
||||
init: RequestInit,
|
||||
extraOptions?: ExtraOptionsProps,
|
||||
) => {
|
||||
const headers = new Headers(init.headers);
|
||||
|
||||
if (!headers.get("Content-Type")) {
|
||||
headers.set("Content-Type", "application/json");
|
||||
}
|
||||
|
||||
if (extraOptions?.isAccessTokenRequird !== false) {
|
||||
const accessToken = await getValidAccessToken(
|
||||
process.env.NEXT_PUBLIC_IKON_API_URL || "",
|
||||
);
|
||||
|
||||
if (!accessToken?.trim()) {
|
||||
redirect("/login.html");
|
||||
}
|
||||
|
||||
headers.set("Authorization", `Bearer ${accessToken.trim()}`);
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
...init,
|
||||
headers,
|
||||
});
|
||||
|
||||
const contentType = response.headers.get("Content-Type");
|
||||
|
||||
if (!response.ok) {
|
||||
let body = "";
|
||||
try {
|
||||
body = contentType?.includes("application/json")
|
||||
? await response.json()
|
||||
: await response.text();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
const message =
|
||||
typeof body === "string"
|
||||
? body
|
||||
: (() => {
|
||||
try {
|
||||
return JSON.stringify(body);
|
||||
} catch {
|
||||
return String(body);
|
||||
}
|
||||
})();
|
||||
console.error(
|
||||
`API Request Failed - ${init.method} ${url}: HTTP ${response.status} ${message}`,
|
||||
);
|
||||
if (extraOptions?.isReturnErrorResult) {
|
||||
return body;
|
||||
}
|
||||
throw new Error(`HTTP ${response.status}: ${message}`);
|
||||
}
|
||||
|
||||
return contentType?.includes("application/json")
|
||||
? await response.json()
|
||||
: await response.text();
|
||||
};
|
||||
36
frontend/app/utils/api/companyData/gradeApi.ts/index.ts
Normal file
36
frontend/app/utils/api/companyData/gradeApi.ts/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { baseApiRequest } from "../../apiRequests/baseApiRequest";
|
||||
import { GradeResponse, GradeResponseDto } from "./type";
|
||||
|
||||
const PROJECT_MANAGEMENT_BASE_URL = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1`;
|
||||
|
||||
export const getAllGrade = async (): Promise<GradeResponse> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/grades`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: ["/grades"],
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getGradeById = async (id: string): Promise<GradeResponseDto> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/grades/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: [`/grades/${id}`],
|
||||
},
|
||||
);
|
||||
};
|
||||
34
frontend/app/utils/api/companyData/gradeApi.ts/type.ts
Normal file
34
frontend/app/utils/api/companyData/gradeApi.ts/type.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export interface GradeResponseDto {
|
||||
id: string;
|
||||
accountId: string;
|
||||
grade: string;
|
||||
}
|
||||
|
||||
export interface SortInfo {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
}
|
||||
|
||||
export interface PageableInfo {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
sort: SortInfo;
|
||||
offset: number;
|
||||
paged: boolean;
|
||||
unpaged: boolean;
|
||||
}
|
||||
|
||||
export interface GradeResponse {
|
||||
content: GradeResponseDto[];
|
||||
pageable: PageableInfo;
|
||||
last: boolean;
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
sort: SortInfo;
|
||||
first: boolean;
|
||||
number: number;
|
||||
size: number;
|
||||
numberOfElements: number;
|
||||
empty: boolean;
|
||||
}
|
||||
36
frontend/app/utils/api/companyData/roleApi.ts/index.ts
Normal file
36
frontend/app/utils/api/companyData/roleApi.ts/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { baseApiRequest } from "../../apiRequests/baseApiRequest";
|
||||
import { RoleResponse, RoleResponseDto } from "./type";
|
||||
|
||||
const PROJECT_MANAGEMENT_BASE_URL = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1`;
|
||||
|
||||
export const getAllRoles = async (): Promise<RoleResponse> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/roles`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: ["/roles"],
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getRoleById = async (id: string): Promise<RoleResponseDto> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/roles/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: [`/roles/${id}`],
|
||||
},
|
||||
);
|
||||
};
|
||||
34
frontend/app/utils/api/companyData/roleApi.ts/type.ts
Normal file
34
frontend/app/utils/api/companyData/roleApi.ts/type.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export interface RoleResponseDto {
|
||||
id: string;
|
||||
accountId: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
export interface SortInfo {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
}
|
||||
|
||||
export interface PageableInfo {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
sort: SortInfo;
|
||||
offset: number;
|
||||
paged: boolean;
|
||||
unpaged: boolean;
|
||||
}
|
||||
|
||||
export interface RoleResponse {
|
||||
content: RoleResponseDto[];
|
||||
pageable: PageableInfo;
|
||||
last: boolean;
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
sort: SortInfo;
|
||||
first: boolean;
|
||||
number: number;
|
||||
size: number;
|
||||
numberOfElements: number;
|
||||
empty: boolean;
|
||||
}
|
||||
43
frontend/app/utils/api/employeeDetails/index.tsx
Normal file
43
frontend/app/utils/api/employeeDetails/index.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
|
||||
const PROJECT_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1`;
|
||||
// const USER_API =
|
||||
// "https://ikoncloud-dev.keross.com/ikon-api/platform/user/current";
|
||||
|
||||
// READ
|
||||
export const getGrades = async () => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/grades`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const getRoles = async () => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/roles`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const getEmployees = async () => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/employees`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: ["/roles"],
|
||||
},
|
||||
);
|
||||
};
|
||||
109
frontend/app/utils/api/fxRate/index.tsx
Normal file
109
frontend/app/utils/api/fxRate/index.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
import { FxRateResponse } from "./type";
|
||||
|
||||
// interface FxRateApiResponse {
|
||||
// id: string;
|
||||
// year: string;
|
||||
// currency: string;
|
||||
// rate: string;
|
||||
// }
|
||||
|
||||
// interface PaginatedResponse<T> {
|
||||
// content: T[];
|
||||
// }
|
||||
|
||||
const PROJECT_MANAGEMENT_BASE_URL = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1`;
|
||||
|
||||
export const getAllFXRate = async (): Promise<FxRateResponse> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/fx-rate`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: ["/fx-rate"],
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getFxRateByYear = async (
|
||||
year: string,
|
||||
): Promise<FxRateResponse> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/fx-rate/year=${year}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: [`/fx-rate/year=${year}`],
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
// export type FxRateMap = Map<string, Map<string, number>>;
|
||||
|
||||
// export async function createFxRateMap(): Promise<FxRateMap> {
|
||||
// const fxRateMap: FxRateMap = new Map();
|
||||
|
||||
// try {
|
||||
// console.log("Fetching FX Rates for map...");
|
||||
|
||||
// const response = await baseApiRequest(
|
||||
// "${process.env.SALES_CRM_API_URL}/fxrate",
|
||||
// {
|
||||
// method: "GET",
|
||||
// credentials: "include",
|
||||
// },
|
||||
// );
|
||||
|
||||
// const paginatedData = response as PaginatedResponse<FxRateApiResponse>;
|
||||
|
||||
// if (!paginatedData || !Array.isArray(paginatedData.content)) {
|
||||
// console.error(
|
||||
// "Invalid response structure received from FX Rate API:",
|
||||
// paginatedData,
|
||||
// );
|
||||
// throw new Error("Failed to fetch FX Rates: Invalid data format.");
|
||||
// }
|
||||
|
||||
// const rates: FxRateApiResponse[] = paginatedData.content;
|
||||
// console.log(`Processing ${rates.length} FX rates...`);
|
||||
|
||||
// rates.forEach((rateData) => {
|
||||
// const year = rateData.year;
|
||||
// const currency = rateData.currency.toUpperCase();
|
||||
// const rateValue = parseFloat(rateData.rate);
|
||||
|
||||
// if (!year || !currency || isNaN(rateValue)) {
|
||||
// console.warn("Skipping invalid rate data:", rateData);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!fxRateMap.has(year)) {
|
||||
// fxRateMap.set(year, new Map<string, number>());
|
||||
// }
|
||||
// const yearMap = fxRateMap.get(year)!;
|
||||
// yearMap.set(currency, rateValue);
|
||||
// });
|
||||
|
||||
// console.log("FX Rate Map created successfully:", fxRateMap);
|
||||
// return fxRateMap;
|
||||
// } catch (error) {
|
||||
// console.error("Error creating FX Rate Map:", error);
|
||||
// let errorMessage = "An unknown error occurred";
|
||||
// if (error instanceof Error) {
|
||||
// errorMessage = error.message;
|
||||
// } else if (typeof error === "string") {
|
||||
// errorMessage = error;
|
||||
// }
|
||||
// throw new Error(`Failed to create FX Rate Map: ${errorMessage}`);
|
||||
// }
|
||||
// }
|
||||
65
frontend/app/utils/api/fxRate/type.ts
Normal file
65
frontend/app/utils/api/fxRate/type.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
export interface FxRateDetail {
|
||||
id: string;
|
||||
currency: string;
|
||||
fxRate: number;
|
||||
activeStatus: boolean;
|
||||
year: string;
|
||||
}
|
||||
|
||||
export interface FxRateYearGroup {
|
||||
[year: string]: {
|
||||
[key: string]: FxRateDetail;
|
||||
};
|
||||
}
|
||||
|
||||
export interface FxContentItem {
|
||||
fxRateDetails: FxRateYearGroup;
|
||||
}
|
||||
|
||||
export interface SortInfo {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
}
|
||||
|
||||
export interface PageableInfo {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
sort: SortInfo;
|
||||
offset: number;
|
||||
paged: boolean;
|
||||
unpaged: boolean;
|
||||
}
|
||||
|
||||
export interface FxRateEntry {
|
||||
id: string;
|
||||
currency: string;
|
||||
fxRate: number;
|
||||
activeStatus: boolean;
|
||||
year: string;
|
||||
}
|
||||
|
||||
export interface FxRateDetails {
|
||||
[key: string]: {
|
||||
[key: string]: FxRateEntry;
|
||||
};
|
||||
}
|
||||
|
||||
export interface FxRateResponse {
|
||||
content: FxContentItem[];
|
||||
pageable: PageableInfo;
|
||||
last: boolean;
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
sort: SortInfo;
|
||||
first: boolean;
|
||||
number: number;
|
||||
size: number;
|
||||
numberOfElements: number;
|
||||
empty: boolean;
|
||||
}
|
||||
|
||||
export interface CurrencyOption {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
55
frontend/app/utils/api/issueApi/index.tsx
Normal file
55
frontend/app/utils/api/issueApi/index.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { IssueData } from "../../interface/issue";
|
||||
import { RiskData } from "../../interface/risk";
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
|
||||
const ISSUE_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/issues`;
|
||||
|
||||
|
||||
// CREATE
|
||||
export const createIssueApi = async (issue: IssueData) => {
|
||||
return baseApiRequest(
|
||||
ISSUE_API,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(issue),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
|
||||
export const updateIssueApi = async (issueIdentifier: string, updatedIssue: IssueData) => {
|
||||
return baseApiRequest(
|
||||
`${ISSUE_API}/${issueIdentifier}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(updatedIssue),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
// READ
|
||||
export const issuesApi = async (projectIdentifier: string) => {
|
||||
return baseApiRequest(
|
||||
`${ISSUE_API}/project/${projectIdentifier}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const getIssueByIdentifierApi = async (issueId: string) => {
|
||||
return baseApiRequest(
|
||||
`${ISSUE_API}/${issueId}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
69
frontend/app/utils/api/meetingApi/index.tsx
Normal file
69
frontend/app/utils/api/meetingApi/index.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
import { MeetingData } from "@/app/main/planning/projects/[projectIdentifier]/component/momTab/components/meetingForm/types";
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
|
||||
const MEETING_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/meetings`;
|
||||
|
||||
|
||||
// CREATE
|
||||
export const createMeetingApi = async (meeting: MeetingData) => {
|
||||
return baseApiRequest(
|
||||
MEETING_API,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(meeting),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// READ ALL BY PROJECT ID
|
||||
export const meetingsApi = async (projectIdentifier: string) => {
|
||||
return baseApiRequest(
|
||||
`${MEETING_API}/project/${projectIdentifier}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// READ BY ID
|
||||
export const getMeetingByIdApi = async (meetingId: string) => {
|
||||
return baseApiRequest(
|
||||
`${MEETING_API}/${meetingId}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// UPDATE
|
||||
export const updateMeetingApi = async (meetingId: string, updatedMeeting: MeetingData) => {
|
||||
return baseApiRequest(
|
||||
`${MEETING_API}/${meetingId}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(updatedMeeting),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// DELETE
|
||||
export const deleteMeetingApi = async (meetingId: string) => {
|
||||
return baseApiRequest(
|
||||
`${MEETING_API}/${meetingId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
26
frontend/app/utils/api/productDashboardApi/index.tsx
Normal file
26
frontend/app/utils/api/productDashboardApi/index.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
import { DashboardWidgetsResponseDto, StatusWiseProjectResponseData } from "./types";
|
||||
|
||||
const PROJECT_DASHBOARD_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/dashboard`;
|
||||
|
||||
export const getWidgetsData: () => Promise<DashboardWidgetsResponseDto> = async () => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_DASHBOARD_API}/widgets`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const getStatusWiseProjectCount: () => Promise<StatusWiseProjectResponseData> = async () => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_DASHBOARD_API}/status-wise-projects`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
10
frontend/app/utils/api/productDashboardApi/types.ts
Normal file
10
frontend/app/utils/api/productDashboardApi/types.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface StatusWiseProjectResponseData {
|
||||
status: string;
|
||||
projectCount: number;
|
||||
}
|
||||
|
||||
export interface DashboardWidgetsResponseDto {
|
||||
totalProjects: number;
|
||||
totalIssues: number;
|
||||
totalRisksCount: number;
|
||||
}
|
||||
48
frontend/app/utils/api/productOfProjectApi/index.tsx
Normal file
48
frontend/app/utils/api/productOfProjectApi/index.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { ProjectFormData } from "@/app/main/planning/projects/projectModal/zodProject";
|
||||
import { Project } from "@/app/main/planning/projects/types/project";
|
||||
import { ProductOfProject } from "../../interface/productOfProject";
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
|
||||
const PROJECT_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/projects`;
|
||||
const USER_API =
|
||||
"https://ikoncloud-dev.keross.com/ikon-api/platform/user/current";
|
||||
|
||||
// READ
|
||||
export const getProductsApi = async (projectId: string) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectId}/products`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
// UPDATE
|
||||
export const updateProductApi = async (product: ProductOfProject) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${product.projectIdentifier}/products/${product.productIdentifier}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(product),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
// WORKFLOW TRANSITION
|
||||
export const transitionProductStatusApi = async (
|
||||
projectId: string,
|
||||
productId: string,
|
||||
targetStatus: string,
|
||||
) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectId}/products/${productId}/transition`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({ targetStatus }),
|
||||
},
|
||||
{ isAccessTokenRequird: true, isReturnErrorResult: true },
|
||||
);
|
||||
};
|
||||
112
frontend/app/utils/api/productOfProjectApi/type.ts
Normal file
112
frontend/app/utils/api/productOfProjectApi/type.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
export interface ProductPSData {
|
||||
productIdentifier: string; // UUID
|
||||
|
||||
dealName: string;
|
||||
projectManager: string;
|
||||
productStatus: string;
|
||||
updatedOn: string;
|
||||
updatedBy: string;
|
||||
dealStatus: string;
|
||||
dealIdentifier: string; // UUID
|
||||
leadIdentifier: string; // UUID
|
||||
|
||||
quotation: Record<string, QuotationItemDto>;
|
||||
|
||||
productType: string;
|
||||
productDescription: string;
|
||||
|
||||
scheduleData: ScheduleDataDto;
|
||||
|
||||
resourceDataWithAllocation: ResourceAllocationDto[];
|
||||
|
||||
discountPercent: number | null;
|
||||
expenseDetails: Record<string, ExpenseDetailDto>;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
export interface QuotationItemDto {
|
||||
id: string;
|
||||
role: string;
|
||||
totalFTE: number;
|
||||
scr: number;
|
||||
expenses: number;
|
||||
otherCosts: number;
|
||||
billingAmount: number;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
export interface ScheduleDataDto {
|
||||
task: TaskDto[];
|
||||
dependency: DependencyDto[];
|
||||
group: Record<string, GroupItem>;
|
||||
}
|
||||
|
||||
export interface GroupItem {
|
||||
id?: string | number;
|
||||
name?: string;
|
||||
type?: string;
|
||||
order?: number;
|
||||
color?: string;
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
export interface TaskDto {
|
||||
id: number;
|
||||
parentId: number;
|
||||
taskName: string;
|
||||
taskDuration: number;
|
||||
taskPredecessor: string;
|
||||
dependencyType: number;
|
||||
taskColour: string;
|
||||
delayDuration: number;
|
||||
taskDescription: string;
|
||||
taskStart: string;
|
||||
taskEnd: string;
|
||||
milestoneTask: boolean;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
export interface DependencyDto {
|
||||
id: number;
|
||||
predecessorId: number;
|
||||
dependencyType: number;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
export interface ResourceAllocationDto {
|
||||
id?: string;
|
||||
allocation: Record<string, number>;
|
||||
detailedAllocation: Record<string, DetailedAllocationValue>;
|
||||
resourceType: string;
|
||||
role: string;
|
||||
gradeId: number;
|
||||
employeeName: string;
|
||||
taskName: string;
|
||||
resourceId: string;
|
||||
taskId: number;
|
||||
}
|
||||
|
||||
export interface DetailedAllocationValue {
|
||||
hours?: number;
|
||||
date?: string;
|
||||
cost?: number;
|
||||
comments?: string;
|
||||
approved?: boolean;
|
||||
}
|
||||
|
||||
|
||||
export interface ExpenseDetailDto {
|
||||
expenseName: string;
|
||||
location: string;
|
||||
currency: string;
|
||||
cost: number;
|
||||
quantity: number;
|
||||
totalCost: number;
|
||||
remarks: string;
|
||||
}
|
||||
48
frontend/app/utils/api/productOfprojectsApi/index.tsx
Normal file
48
frontend/app/utils/api/productOfprojectsApi/index.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { UUID } from "crypto";
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
|
||||
const PROJECT_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/projects`;
|
||||
const USER_API =
|
||||
"https://ikoncloud-dev.keross.com/ikon-api/platform/user/current";
|
||||
|
||||
|
||||
// READ
|
||||
export const getAllProductsByProject = async (projectIdentifier: UUID) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectIdentifier}/products`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store", // optional but recommended for fresh data
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
export const getProductById = async (projectId: UUID, productIdentifier: UUID) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectId}/products/${productIdentifier}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
|
||||
// UPDATE
|
||||
export const updateProduct = async (projectId: UUID, productIdentifier: UUID, updatedProduct: any) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectId}/products/${productIdentifier}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(updatedProduct),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
85
frontend/app/utils/api/productsResourceAllocation/index.tsx
Normal file
85
frontend/app/utils/api/productsResourceAllocation/index.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
import { UUID } from "crypto";
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
|
||||
const PRODUCT_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/products`;
|
||||
|
||||
// Allocation payload shape
|
||||
export interface ProductAllocation {
|
||||
id?: string;
|
||||
allocation: Record<string, number>;
|
||||
detailedAllocation: Record<string, Record<string, any>>;
|
||||
resourceType: string;
|
||||
role: string;
|
||||
gradeId: number;
|
||||
employeeName: string;
|
||||
taskName: string;
|
||||
resourceId: string;
|
||||
taskId: number;
|
||||
}
|
||||
|
||||
// List allocations for a product
|
||||
export const getResourceAllocations = async (productIdentifier: UUID) => {
|
||||
return baseApiRequest(
|
||||
`${PRODUCT_API}/${productIdentifier}/resource-allocations`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
|
||||
// Get a single allocation
|
||||
export const getAllocation = async (productIdentifier: UUID, allocationIdentifier: UUID) => {
|
||||
return baseApiRequest(
|
||||
`${PRODUCT_API}/${productIdentifier}/resource-allocations/${allocationIdentifier}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
|
||||
// Create allocation
|
||||
export const createAllocation = async (productIdentifier: UUID, allocation: ProductAllocation) => {
|
||||
return baseApiRequest(
|
||||
`${PRODUCT_API}/${productIdentifier}/resource-allocations`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(allocation),
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
|
||||
// Update allocation
|
||||
export const updateAllocation = async (
|
||||
productIdentifier: UUID,
|
||||
allocationIdentifier: UUID,
|
||||
updatedAllocation: ProductAllocation
|
||||
) => {
|
||||
return baseApiRequest(
|
||||
`${PRODUCT_API}/${productIdentifier}/resource-allocations/${allocationIdentifier}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(updatedAllocation),
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
|
||||
// Delete allocation
|
||||
export const deleteAllocation = async (productIdentifier: UUID, allocationIdentifier: UUID) => {
|
||||
return baseApiRequest(
|
||||
`${PRODUCT_API}/${productIdentifier}/resource-allocations/${allocationIdentifier}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
111
frontend/app/utils/api/projectApi/index.tsx
Normal file
111
frontend/app/utils/api/projectApi/index.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import { ProjectFormData } from "@/app/main/planning/projects/projectModal/zodProject";
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
import { Project } from "@/app/main/planning/projects/types/project";
|
||||
|
||||
const PROJECT_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/projects`;
|
||||
const USER_API =
|
||||
`${process.env.NEXT_PUBLIC_IKON_API_URL}/platform/user/current`;
|
||||
|
||||
// CREATE
|
||||
export const createProjectApi = async (project: ProjectFormData) => {
|
||||
return baseApiRequest(
|
||||
PROJECT_API,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(project),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
// READ
|
||||
export const getProjectsApi = async () => {
|
||||
return baseApiRequest(
|
||||
PROJECT_API,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const getProjectByIdentifierApi = async (projectId: string) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectId}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
// UPDATE
|
||||
export const updateProjectApi = async (project: Project) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${project.projectIdentifier}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(project),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const getScheduleApi = async (projectId: string) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectId}/schedules`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store"
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const getAllSchedulesApi = async () => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/schedules`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store"
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const saveScheduleApi = async (
|
||||
projectId: string,
|
||||
scheduleData: { task: any[]; dependency: any[]; group?: Record<string, any> },
|
||||
) => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/${projectId}/schedules`,
|
||||
{ method: "PUT", body: JSON.stringify(scheduleData) },
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
export const getUsersApi = async () => {
|
||||
return baseApiRequest(
|
||||
USER_API,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getAllActiveProjectsTimelineApi = async () => {
|
||||
return baseApiRequest(
|
||||
`${PROJECT_API}/active-projects-timeline`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
88
frontend/app/utils/api/projectManager/index.tsx
Normal file
88
frontend/app/utils/api/projectManager/index.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
import { ManagerMemberships, Role, RoleMembership } from "./projectManager";
|
||||
|
||||
|
||||
const API_BASE_URL = "https://ikoncloud-dev.keross.com/ikon-api";
|
||||
|
||||
export const getAllRoles = async (): Promise<Role[]> => {
|
||||
return await baseApiRequest(
|
||||
`${API_BASE_URL}/role`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const getRoleMemberships = async (roleId: string): Promise<RoleMembership[]> => {
|
||||
return await baseApiRequest(
|
||||
`${API_BASE_URL}/role/${roleId}/membership`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const getRoleIdByName = (
|
||||
roles: Role[],
|
||||
roleName: string
|
||||
): string | undefined => {
|
||||
if (!roles || !Array.isArray(roles)) {
|
||||
console.error("getRoleIdByName received invalid roles data:", roles);
|
||||
return undefined;
|
||||
}
|
||||
const foundRole = roles.find((role) => role.roleName === roleName);
|
||||
|
||||
return foundRole?.roleId;
|
||||
};
|
||||
|
||||
export const getManagerMemberships = async (): Promise<ManagerMemberships> => {
|
||||
try {
|
||||
const response = await getAllRoles();
|
||||
const allRoles = Array.isArray(response) ? response : (response?.content || []);
|
||||
|
||||
const projectManagerId = getRoleIdByName(allRoles, "Project manager");
|
||||
const accountManagerId = getRoleIdByName(allRoles, "Account Manager");
|
||||
|
||||
if (!projectManagerId) {
|
||||
console.warn("Could not find roleId for 'Project Manager'");
|
||||
}
|
||||
if (!accountManagerId) {
|
||||
console.warn("Could not find roleId for 'Account Manager'");
|
||||
}
|
||||
|
||||
const pmPromise = projectManagerId
|
||||
? getRoleMemberships(projectManagerId)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const amPromise = accountManagerId
|
||||
? getRoleMemberships(accountManagerId)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const [projectManagerMembers, accountManagerMembers] = await Promise.all([
|
||||
pmPromise,
|
||||
amPromise,
|
||||
]);
|
||||
|
||||
return {
|
||||
projectManagerMembers,
|
||||
accountManagerMembers,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error in getManagerMemberships:", error);
|
||||
return {
|
||||
projectManagerMembers: [],
|
||||
accountManagerMembers: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
54
frontend/app/utils/api/projectManager/projectManager.ts
Normal file
54
frontend/app/utils/api/projectManager/projectManager.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export interface IkonGroup {
|
||||
groupId: string;
|
||||
groupName: string;
|
||||
softwareId: string;
|
||||
accountId: string | null;
|
||||
groupType: "STATIC" | "DYNAMIC" | string;
|
||||
active: boolean;
|
||||
groupDescription: string;
|
||||
}
|
||||
|
||||
export interface Role {
|
||||
roleId: string;
|
||||
roleName: string;
|
||||
active: boolean;
|
||||
softwareId: string;
|
||||
roleDescription: string;
|
||||
ikonGroups: IkonGroup[];
|
||||
}
|
||||
|
||||
export interface RoleMembership {
|
||||
roleMembershipId: string;
|
||||
userId: string;
|
||||
accountId: string;
|
||||
roleId: string;
|
||||
}
|
||||
|
||||
export interface ManagerMemberships {
|
||||
projectManagerMembers: RoleMembership[];
|
||||
accountManagerMembers: RoleMembership[];
|
||||
}
|
||||
|
||||
|
||||
export interface User {
|
||||
userId: string;
|
||||
userName: string;
|
||||
userLogin: string;
|
||||
userPhone: string | null;
|
||||
userEmail: string;
|
||||
userThumbnail: string | null;
|
||||
userType: string;
|
||||
active: boolean;
|
||||
dateOfBirth: string | null;
|
||||
userProfileImage: string | null;
|
||||
userDescription: string | null;
|
||||
userDesignation: string | null;
|
||||
invitedUser: boolean;
|
||||
userDeleted: boolean;
|
||||
}
|
||||
|
||||
export interface UserInfo {
|
||||
userName: string;
|
||||
userLogin: string;
|
||||
userEmail: string;
|
||||
}
|
||||
54
frontend/app/utils/api/riskApi/index.tsx
Normal file
54
frontend/app/utils/api/riskApi/index.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { RiskData } from "../../interface/risk";
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
|
||||
const RISK_API = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1/risks`;
|
||||
|
||||
|
||||
// CREATE
|
||||
export const createRiskApi = async (Risk: RiskData) => {
|
||||
return baseApiRequest(
|
||||
RISK_API,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(Risk),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
|
||||
export const updateRiskApi = async (riskIdentifier: string, updatedRisk: RiskData) => {
|
||||
return baseApiRequest(
|
||||
`${RISK_API}/${riskIdentifier}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify(updatedRisk),
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
// READ
|
||||
export const risksApi = async () => {
|
||||
return baseApiRequest(
|
||||
RISK_API,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true },
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const getRiskByIdentifierApi = async (riskId: string) => {
|
||||
return baseApiRequest(
|
||||
`${RISK_API}/${riskId}`,
|
||||
{
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
},
|
||||
{ isAccessTokenRequird: true }
|
||||
);
|
||||
};
|
||||
65
frontend/app/utils/api/user-dashboard-platform/index.tsx
Normal file
65
frontend/app/utils/api/user-dashboard-platform/index.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
import { Role, User, RoleMembership } from "./type";
|
||||
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL;
|
||||
const IKON_API_URL = process.env.NEXT_PUBLIC_IKON_API_URL;
|
||||
|
||||
export const getAllRoles = async (): Promise<Role[]> => {
|
||||
return await baseApiRequest(
|
||||
`${API_BASE_URL}/role`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: ["/roles"],
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const getAllUsers = async (): Promise<User[]> => {
|
||||
return await baseApiRequest(
|
||||
`${IKON_API_URL}/platform/user/current`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: ["/platform/user/current"],
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const getUserById = async (userId: string): Promise<User | null> => {
|
||||
return await baseApiRequest(
|
||||
`${IKON_API_URL}/platform/user/${userId}`, // Assuming this endpoint pattern
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: [`/platform/user/${userId}`],
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const getRoleMemberships = async (roleId: string): Promise<RoleMembership[]> => {
|
||||
return await baseApiRequest(
|
||||
`${API_BASE_URL}/role/${roleId}/membership`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,145 @@
|
||||
import { getAllRoles, getAllUsers, getRoleMemberships, getUserById } from ".";
|
||||
import { ManagerMemberships, Role, UserInfo } from "./type"; // Import User
|
||||
|
||||
export const getRoleIdByName = (
|
||||
roles: Role[],
|
||||
roleName: string
|
||||
): string | undefined => {
|
||||
if (!roles || !Array.isArray(roles)) {
|
||||
console.error("getRoleIdByName received invalid roles data:", roles);
|
||||
return undefined;
|
||||
}
|
||||
const foundRole = roles.find((role) => role.roleName === roleName);
|
||||
|
||||
return foundRole?.roleId;
|
||||
};
|
||||
|
||||
export const findUsersInRole = async (roleName: string) => {
|
||||
try {
|
||||
console.log("Step 1: Fetching all roles...");
|
||||
const allRoles = await getAllRoles();
|
||||
|
||||
console.log(`Step 2: Finding ID for role "${roleName}"...`);
|
||||
const roleId = getRoleIdByName(allRoles, roleName);
|
||||
|
||||
if (!roleId) {
|
||||
console.error(`Error: Role "${roleName}" not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Found roleId: ${roleId}`);
|
||||
|
||||
console.log("Step 3: Fetching memberships for this role...");
|
||||
const memberships = await getRoleMemberships(roleId);
|
||||
|
||||
if (memberships.length === 0) {
|
||||
console.log(`No users found for role "${roleName}".`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Success! Found ${memberships.length} user(s) in "${roleName}":`
|
||||
);
|
||||
|
||||
const userIds = memberships.map((m: { userId: string }) => m.userId);
|
||||
console.log(userIds);
|
||||
return userIds;
|
||||
} catch (error) {
|
||||
console.error("An error occurred during the process:", error);
|
||||
}
|
||||
};
|
||||
|
||||
export const getManagerMemberships = async (): Promise<ManagerMemberships> => {
|
||||
try {
|
||||
const response = await getAllRoles();
|
||||
const allRoles = Array.isArray(response) ? response : (response?.content || []);
|
||||
console.log("rolesss", allRoles);
|
||||
const projectManagerId = getRoleIdByName(allRoles, "Project manager");
|
||||
const accountManagerId = getRoleIdByName(allRoles, "Account Manager");
|
||||
|
||||
if (!projectManagerId) {
|
||||
console.warn("Could not find roleId for 'Project Manager'");
|
||||
}
|
||||
if (!accountManagerId) {
|
||||
console.warn("Could not find roleId for 'Account Manager'");
|
||||
}
|
||||
|
||||
const pmPromise = projectManagerId
|
||||
? getRoleMemberships(projectManagerId)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const amPromise = accountManagerId
|
||||
? getRoleMemberships(accountManagerId)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const [projectManagerMembers, accountManagerMembers] = await Promise.all([
|
||||
pmPromise,
|
||||
amPromise,
|
||||
]);
|
||||
|
||||
return {
|
||||
projectManagerMembers,
|
||||
accountManagerMembers,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error in getManagerMemberships:", error);
|
||||
return {
|
||||
projectManagerMembers: [],
|
||||
accountManagerMembers: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const createUserMaps = async (): Promise<{
|
||||
nameMap: Map<string, string>;
|
||||
designationMap: Map<string, string | null>;
|
||||
}> => {
|
||||
const nameMap = new Map<string, string>();
|
||||
const designationMap = new Map<string, string | null>();
|
||||
|
||||
try {
|
||||
const response = await getAllUsers();
|
||||
const userArray = response ?? response;
|
||||
|
||||
if (!userArray || !Array.isArray(userArray) || userArray.length === 0) {
|
||||
return { nameMap, designationMap };
|
||||
} else {
|
||||
for (const user of userArray) {
|
||||
if (user?.userId) {
|
||||
nameMap.set(user.userId, user.userName);
|
||||
designationMap.set(user.userId, user.userDesignation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { nameMap, designationMap };
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch users and create maps:", error);
|
||||
return { nameMap, designationMap };
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserNameById = async (
|
||||
userId: string
|
||||
): Promise<string | undefined> => {
|
||||
try {
|
||||
const user = await getUserById(userId);
|
||||
return user?.userName;
|
||||
} catch (error) {
|
||||
console.error("Failed to get user name by ID:", error);
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserInfo = async (userId: string): Promise<UserInfo | null> => {
|
||||
const user = await getUserById(userId);
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
userName: user.userName,
|
||||
userLogin: user.userLogin,
|
||||
userEmail: user.userEmail,
|
||||
};
|
||||
};
|
||||
54
frontend/app/utils/api/user-dashboard-platform/type.ts
Normal file
54
frontend/app/utils/api/user-dashboard-platform/type.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export interface IkonGroup {
|
||||
groupId: string;
|
||||
groupName: string;
|
||||
softwareId: string;
|
||||
accountId: string | null;
|
||||
groupType: "STATIC" | "DYNAMIC" | string;
|
||||
active: boolean;
|
||||
groupDescription: string;
|
||||
}
|
||||
|
||||
export interface Role {
|
||||
roleId: string;
|
||||
roleName: string;
|
||||
active: boolean;
|
||||
softwareId: string;
|
||||
roleDescription: string;
|
||||
ikonGroups: IkonGroup[];
|
||||
}
|
||||
|
||||
export interface RoleMembership {
|
||||
roleMembershipId: string;
|
||||
userId: string;
|
||||
accountId: string;
|
||||
roleId: string;
|
||||
}
|
||||
|
||||
export interface ManagerMemberships {
|
||||
projectManagerMembers: RoleMembership[];
|
||||
accountManagerMembers: RoleMembership[];
|
||||
}
|
||||
|
||||
|
||||
export interface User {
|
||||
userId: string;
|
||||
userName: string;
|
||||
userLogin: string;
|
||||
userPhone: string | null;
|
||||
userEmail: string;
|
||||
userThumbnail: string | null;
|
||||
userType: string;
|
||||
active: boolean;
|
||||
dateOfBirth: string | null;
|
||||
userProfileImage: string | null;
|
||||
userDescription: string | null;
|
||||
userDesignation: string | null;
|
||||
invitedUser: boolean;
|
||||
userDeleted: boolean;
|
||||
}
|
||||
|
||||
export interface UserInfo {
|
||||
userName: string;
|
||||
userLogin: string;
|
||||
userEmail: string;
|
||||
}
|
||||
38
frontend/app/utils/api/workingDays/index.ts
Normal file
38
frontend/app/utils/api/workingDays/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { baseApiRequest } from "../apiRequests/baseApiRequest";
|
||||
import { WorkingDaysResponse } from "./type";
|
||||
|
||||
const PROJECT_MANAGEMENT_BASE_URL = `${process.env.NEXT_PUBLIC_PROJECT_MANAGEMENT_API_URL}/api/v1`;
|
||||
|
||||
export const getAllWorkingDays = async (): Promise<WorkingDaysResponse> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/working-days`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: ["/working-days"],
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const getWorkingDaysByYear = async (
|
||||
year: string,
|
||||
): Promise<WorkingDaysResponse> => {
|
||||
return await baseApiRequest(
|
||||
`${PROJECT_MANAGEMENT_BASE_URL}/working-days/year/${year}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
},
|
||||
{
|
||||
isAccessTokenRequird: true,
|
||||
revalidatePaths: [`/working-days/year/${year}`],
|
||||
},
|
||||
);
|
||||
};
|
||||
40
frontend/app/utils/api/workingDays/type.ts
Normal file
40
frontend/app/utils/api/workingDays/type.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
export interface WorkingDaysMonthDto {
|
||||
year: string;
|
||||
month: string;
|
||||
workingDays: number;
|
||||
}
|
||||
|
||||
export interface WorkingDaysResponseDto {
|
||||
workingId: string;
|
||||
accountIdentifier: string;
|
||||
workingDaysDetails: Record<string, Record<string, WorkingDaysMonthDto>>;
|
||||
}
|
||||
|
||||
export interface WorkingDaysPageableInfo {
|
||||
offset: number;
|
||||
sort: SortInfo;
|
||||
pageSize: number;
|
||||
paged: boolean;
|
||||
unpaged: boolean;
|
||||
pageNumber: number;
|
||||
}
|
||||
|
||||
export interface SortInfo {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
}
|
||||
|
||||
export interface WorkingDaysResponse {
|
||||
content: WorkingDaysResponseDto[];
|
||||
pageable: WorkingDaysPageableInfo;
|
||||
last: boolean;
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
sort: SortInfo;
|
||||
first: boolean;
|
||||
number: number;
|
||||
size: number;
|
||||
numberOfElements: number;
|
||||
empty: boolean;
|
||||
}
|
||||
186
frontend/app/utils/context/AppCacheContext.tsx
Normal file
186
frontend/app/utils/context/AppCacheContext.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
"use client";
|
||||
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
ReactNode,
|
||||
} from "react";
|
||||
import { getManagerMemberships } from "@/app/utils/api/user-dashboard-platform/mappingFunction";
|
||||
import { getAllUsers } from "@/app/utils/api/user-dashboard-platform";
|
||||
import type {
|
||||
RoleMembership,
|
||||
User,
|
||||
} from "@/app/utils/api/user-dashboard-platform/type";
|
||||
import { getAllFXRate } from "@/app/utils/api/fxRate";
|
||||
import type { FxRateResponse } from "@/app/utils/api/fxRate/type";
|
||||
|
||||
/** year -> currency (upper-cased) -> rate */
|
||||
export type FxRateMap = Map<string, Map<string, number>>;
|
||||
|
||||
type SelectOption = { value: string; label: string };
|
||||
|
||||
interface AppCacheState {
|
||||
/** userId -> userName */
|
||||
userNameMap: Map<string, string>;
|
||||
/** userId -> designation */
|
||||
userDesignationMap: Map<string, string | null>;
|
||||
/** all active (non-deleted) platform users */
|
||||
activeUsers: User[];
|
||||
/** year -> currency -> rate, derived from the raw FX response */
|
||||
fxRateMap: FxRateMap;
|
||||
/** the raw FX rate response (paginated) */
|
||||
fxRateResponse: FxRateResponse | null;
|
||||
/** userId/userName options for users holding the Project Manager role */
|
||||
projectManagerOptions: SelectOption[];
|
||||
/** userId/userName options for users holding the Account Manager role */
|
||||
accountManagerOptions: SelectOption[];
|
||||
isLoading: boolean;
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
const AppCacheContext = createContext<AppCacheState>({
|
||||
userNameMap: new Map(),
|
||||
userDesignationMap: new Map(),
|
||||
activeUsers: [],
|
||||
fxRateMap: new Map(),
|
||||
fxRateResponse: null,
|
||||
projectManagerOptions: [],
|
||||
accountManagerOptions: [],
|
||||
isLoading: true,
|
||||
refresh: () => {},
|
||||
});
|
||||
|
||||
export function AppCacheProvider({ children }: { children: ReactNode }) {
|
||||
const [userNameMap, setUserNameMap] = useState<Map<string, string>>(new Map());
|
||||
const [userDesignationMap, setUserDesignationMap] = useState<
|
||||
Map<string, string | null>
|
||||
>(new Map());
|
||||
const [activeUsers, setActiveUsers] = useState<User[]>([]);
|
||||
const [fxRateMap, setFxRateMap] = useState<FxRateMap>(new Map());
|
||||
const [fxRateResponse, setFxRateResponse] = useState<FxRateResponse | null>(
|
||||
null,
|
||||
);
|
||||
const [projectManagerOptions, setProjectManagerOptions] = useState<
|
||||
SelectOption[]
|
||||
>([]);
|
||||
const [accountManagerOptions, setAccountManagerOptions] = useState<
|
||||
SelectOption[]
|
||||
>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
const load = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const allUsers = await getAllUsers();
|
||||
const usersList: User[] = Array.isArray(allUsers) ? allUsers : [];
|
||||
|
||||
// Build name + designation maps and the active-user list from one fetch
|
||||
const nameMap = new Map<string, string>();
|
||||
const designationMap = new Map<string, string | null>();
|
||||
usersList.forEach((u) => {
|
||||
if (u?.userId) {
|
||||
nameMap.set(u.userId, u.userName);
|
||||
designationMap.set(u.userId, u.userDesignation);
|
||||
}
|
||||
});
|
||||
const activeUserList = usersList.filter(
|
||||
(u) => u.active && !u.userDeleted,
|
||||
);
|
||||
|
||||
const [memberships, rawFxResponse] = await Promise.all([
|
||||
getManagerMemberships(),
|
||||
getAllFXRate(),
|
||||
]);
|
||||
|
||||
// Build FxRateMap (year -> currency -> rate) from the raw response
|
||||
const builtFxRateMap: FxRateMap = new Map();
|
||||
rawFxResponse.content?.forEach((item) => {
|
||||
Object.entries(item.fxRateDetails || {}).forEach(
|
||||
([year, currencyData]) => {
|
||||
if (!currencyData) return;
|
||||
Object.entries(currencyData).forEach(([, rateData]) => {
|
||||
const currency = rateData?.currency?.toUpperCase();
|
||||
const rateValue = rateData?.fxRate;
|
||||
if (
|
||||
!year ||
|
||||
!currency ||
|
||||
rateValue === null ||
|
||||
rateValue === undefined ||
|
||||
isNaN(rateValue)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!builtFxRateMap.has(year)) {
|
||||
builtFxRateMap.set(year, new Map());
|
||||
}
|
||||
builtFxRateMap.get(year)!.set(currency, rateValue);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// Build manager option lists, deduped by userId
|
||||
const toOptions = (members: RoleMembership[]): SelectOption[] => {
|
||||
const options: SelectOption[] = [];
|
||||
members.forEach((member) => {
|
||||
const name = nameMap.get(member.userId);
|
||||
if (name) options.push({ value: member.userId, label: name });
|
||||
});
|
||||
return Array.from(
|
||||
new Map(options.map((opt) => [opt.value, opt])).values(),
|
||||
);
|
||||
};
|
||||
|
||||
if (!cancelled) {
|
||||
setUserNameMap(nameMap);
|
||||
setUserDesignationMap(designationMap);
|
||||
setActiveUsers(activeUserList);
|
||||
setFxRateMap(builtFxRateMap);
|
||||
setFxRateResponse(rawFxResponse);
|
||||
setProjectManagerOptions(toOptions(memberships.projectManagerMembers));
|
||||
setAccountManagerOptions(toOptions(memberships.accountManagerMembers));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("AppCacheProvider: Failed to load maps", err);
|
||||
} finally {
|
||||
if (!cancelled) setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
load();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [refreshKey]);
|
||||
|
||||
const refresh = () => setRefreshKey((k) => k + 1);
|
||||
|
||||
return (
|
||||
<AppCacheContext.Provider
|
||||
value={{
|
||||
userNameMap,
|
||||
userDesignationMap,
|
||||
activeUsers,
|
||||
fxRateMap,
|
||||
fxRateResponse,
|
||||
projectManagerOptions,
|
||||
accountManagerOptions,
|
||||
isLoading,
|
||||
refresh,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AppCacheContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useAppCache(): AppCacheState {
|
||||
return useContext(AppCacheContext);
|
||||
}
|
||||
34
frontend/app/utils/function/nameMapping/index.tsx
Normal file
34
frontend/app/utils/function/nameMapping/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
import { getUsersApi } from "../../api/projectApi";
|
||||
import { User } from "../../api/projectManager/projectManager";
|
||||
|
||||
let userCache: Record<string, string> | null = null;
|
||||
|
||||
export async function buildUserMap(): Promise<Record<string, string>> {
|
||||
if (userCache) return userCache;
|
||||
|
||||
const users = await getUsersApi();
|
||||
|
||||
const map: Record<string, string> = {};
|
||||
|
||||
users.forEach((user: User) => {
|
||||
map[user.userId] = user.userName;
|
||||
});
|
||||
|
||||
userCache = map;
|
||||
return map;
|
||||
}
|
||||
|
||||
export async function getUserNameById(userId: string): Promise<string> {
|
||||
if (!userId) return "—";
|
||||
|
||||
const map = await buildUserMap();
|
||||
return map[userId] || "Unknown User";
|
||||
}
|
||||
|
||||
|
||||
export async function getUserNamesByIds(ids: string[]): Promise<string[]> {
|
||||
const map = await buildUserMap();
|
||||
return ids.map(id => map[id] || "Unknown User");
|
||||
}
|
||||
|
||||
16
frontend/app/utils/function/projectDuration/index.tsx
Normal file
16
frontend/app/utils/function/projectDuration/index.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
export function calculateDurationInDays(
|
||||
startDate?: string | Date,
|
||||
endDate?: string | Date
|
||||
): number | null {
|
||||
if (!startDate || !endDate) return null;
|
||||
|
||||
const start = new Date(startDate);
|
||||
const end = new Date(endDate);
|
||||
|
||||
if (isNaN(start.getTime()) || isNaN(end.getTime())) return null;
|
||||
|
||||
const diffTime = end.getTime() - start.getTime();
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
return diffDays >= 0 ? diffDays : null;
|
||||
}
|
||||
10
frontend/app/utils/interface/expense.ts
Normal file
10
frontend/app/utils/interface/expense.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface Expense {
|
||||
expenseIdentifier?: string;
|
||||
expenseName: string;
|
||||
location: string;
|
||||
currency: string;
|
||||
cost: number;
|
||||
quantity: number;
|
||||
totalCost: number;
|
||||
remarks: string;
|
||||
}
|
||||
35
frontend/app/utils/interface/issue.ts
Normal file
35
frontend/app/utils/interface/issue.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export interface IssueData {
|
||||
issueId?: string;
|
||||
|
||||
issueTitle: string;
|
||||
|
||||
issueProbability: number;
|
||||
|
||||
grossIssueValue: number;
|
||||
|
||||
probableIssueValue: number;
|
||||
|
||||
probableIssueValueInUSD: number;
|
||||
|
||||
issueImpact: string;
|
||||
|
||||
issueOwner: string;
|
||||
|
||||
issueDescription: string;
|
||||
|
||||
mitigationAction?: string;
|
||||
|
||||
projectIdentifier: string;
|
||||
|
||||
financialIssue: boolean;
|
||||
|
||||
issueCreatedDate?: string;
|
||||
|
||||
issueOptionsSelectId?: string;
|
||||
|
||||
issueStatus?: string;
|
||||
|
||||
issueAge?: number;
|
||||
|
||||
effectedSprintId?: string;
|
||||
}
|
||||
48
frontend/app/utils/interface/productOfProject.ts
Normal file
48
frontend/app/utils/interface/productOfProject.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Expense } from "./expense";
|
||||
|
||||
export interface ProductOfProject {
|
||||
productIdentifier: string;
|
||||
projectIdentifier: string;
|
||||
projectName: string;
|
||||
projectManager: string;
|
||||
|
||||
accountId: string;
|
||||
leadIdentifier: string;
|
||||
|
||||
productStatus: string;
|
||||
projectStatus: string;
|
||||
productType: string;
|
||||
productDescription: string;
|
||||
discountPercent: number;
|
||||
|
||||
resourceDataWithAllocation: ResourceAllocationDto[];
|
||||
scheduleData?: { projectIdentifier?: string; productIdentifier?: string; task: any[]; group?: Record<string, any>; dependency?: any[] } | null;
|
||||
|
||||
createdOn: string;
|
||||
createdBy: string;
|
||||
updatedBy: string;
|
||||
updatedOn: string;
|
||||
expenseDetails: Record<string, Expense>;
|
||||
}
|
||||
|
||||
|
||||
export interface ResourceAllocationDto {
|
||||
id?: string;
|
||||
allocation: Record<string, number>;
|
||||
detailedAllocation: Record<string, DetailedAllocationValue>;
|
||||
resourceType: string;
|
||||
role: string;
|
||||
gradeId: number;
|
||||
employeeName: string;
|
||||
taskName: string;
|
||||
resourceId: string;
|
||||
taskId: number;
|
||||
}
|
||||
|
||||
export interface DetailedAllocationValue {
|
||||
hours?: number;
|
||||
date?: string;
|
||||
cost?: number;
|
||||
comments?: string;
|
||||
approved?: boolean;
|
||||
}
|
||||
46
frontend/app/utils/interface/project.ts
Normal file
46
frontend/app/utils/interface/project.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
export interface Project {
|
||||
projectIdentifier: string;
|
||||
|
||||
projectManager: string;
|
||||
projectName: string;
|
||||
projectStatus: string;
|
||||
projectNumber: string;
|
||||
parentProjectNo: string;
|
||||
contractNumber: string;
|
||||
projectClient: string;
|
||||
projectCity: string;
|
||||
projectCountry: string;
|
||||
currency: string;
|
||||
projectImage: string;
|
||||
contractUpload: string;
|
||||
source: string;
|
||||
productType: string;
|
||||
expenses: string;
|
||||
formattedActualRevenueIncludingVAT_deal: string;
|
||||
isCompleted: boolean;
|
||||
groupNotExist: boolean;
|
||||
isDebtRevenue_deal: boolean;
|
||||
projectDescription: string;
|
||||
|
||||
createdById: string;
|
||||
updatedBy: string;
|
||||
projectManagerDelegates: string;
|
||||
|
||||
projectStartDate: string;
|
||||
contractedStartDate: string;
|
||||
contractedEndDate: string;
|
||||
createdOn: string;
|
||||
updatedOn: string;
|
||||
|
||||
projectTeam: string[];
|
||||
projectTeamUnderProjectManager: string[];
|
||||
projectTeamUnderProjectManagerDelegates: string[];
|
||||
|
||||
groupAssigneesEditStr: string;
|
||||
groupAssigneesViewStr: string;
|
||||
|
||||
participants: Record<string, any>;
|
||||
contractedProductIdentifierWiseDataObj: Record<string, any>;
|
||||
|
||||
productIdentifier: string;
|
||||
}
|
||||
18
frontend/app/utils/interface/risk.ts
Normal file
18
frontend/app/utils/interface/risk.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export interface RiskData {
|
||||
riskIdentifier?: string;
|
||||
riskTitle?: string;
|
||||
riskProbability: number;
|
||||
grossRiskValue?: number;
|
||||
probableRiskValue?: number;
|
||||
probableRiskValueInUSD?: number;
|
||||
riskImpact?: string;
|
||||
riskOwner?: string;
|
||||
riskDescription?: string;
|
||||
projectIdentifier?: string;
|
||||
financialRisk?: boolean;
|
||||
riskCreatedDate?: string;
|
||||
riskOptionsSelectId?: string;
|
||||
riskStatus?: string;
|
||||
riskAge?: number;
|
||||
effectedSprintId?: string
|
||||
}
|
||||
14
frontend/app/utils/mapping-functions/date-format/index.ts
Normal file
14
frontend/app/utils/mapping-functions/date-format/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export function formatDate(inputDate: string | null | undefined): string {
|
||||
if (!inputDate) return "";
|
||||
|
||||
const date = new Date(inputDate);
|
||||
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
|
||||
const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
const month = monthNames[date.getMonth()];
|
||||
|
||||
const year = date.getFullYear();
|
||||
|
||||
return `${day}-${month}-${year}`;
|
||||
}
|
||||
197
frontend/app/utils/mapping/country.ts
Normal file
197
frontend/app/utils/mapping/country.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
export const CountryDetails = [
|
||||
{ code: "AF", name: "Afghanistan" },
|
||||
{ code: "AL", name: "Albania" },
|
||||
{ code: "DZ", name: "Algeria" },
|
||||
{ code: "AD", name: "Andorra" },
|
||||
{ code: "AO", name: "Angola" },
|
||||
{ code: "AG", name: "Antigua and Barbuda" },
|
||||
{ code: "AR", name: "Argentina" },
|
||||
{ code: "AM", name: "Armenia" },
|
||||
{ code: "AU", name: "Australia" },
|
||||
{ code: "AT", name: "Austria" },
|
||||
{ code: "AZ", name: "Azerbaijan" },
|
||||
{ code: "BS", name: "Bahamas" },
|
||||
{ code: "BH", name: "Bahrain" },
|
||||
{ code: "BD", name: "Bangladesh" },
|
||||
{ code: "BB", name: "Barbados" },
|
||||
{ code: "BY", name: "Belarus" },
|
||||
{ code: "BE", name: "Belgium" },
|
||||
{ code: "BZ", name: "Belize" },
|
||||
{ code: "BJ", name: "Benin" },
|
||||
{ code: "BT", name: "Bhutan" },
|
||||
{ code: "BO", name: "Bolivia" },
|
||||
{ code: "BA", name: "Bosnia and Herzegovina" },
|
||||
{ code: "BW", name: "Botswana" },
|
||||
{ code: "BR", name: "Brazil" },
|
||||
{ code: "BN", name: "Brunei" },
|
||||
{ code: "BG", name: "Bulgaria" },
|
||||
{ code: "BF", name: "Burkina Faso" },
|
||||
{ code: "BI", name: "Burundi" },
|
||||
{ code: "CV", name: "Cabo Verde" },
|
||||
{ code: "KH", name: "Cambodia" },
|
||||
{ code: "CM", name: "Cameroon" },
|
||||
{ code: "CA", name: "Canada" },
|
||||
{ code: "CF", name: "Central African Republic" },
|
||||
{ code: "TD", name: "Chad" },
|
||||
{ code: "CL", name: "Chile" },
|
||||
{ code: "CN", name: "China" },
|
||||
{ code: "CO", name: "Colombia" },
|
||||
{ code: "KM", name: "Comoros" },
|
||||
{ code: "CG", name: "Congo" },
|
||||
{ code: "CD", name: "Congo (Democratic Republic)" },
|
||||
{ code: "CR", name: "Costa Rica" },
|
||||
{ code: "HR", name: "Croatia" },
|
||||
{ code: "CU", name: "Cuba" },
|
||||
{ code: "CY", name: "Cyprus" },
|
||||
{ code: "CZ", name: "Czechia" },
|
||||
{ code: "DK", name: "Denmark" },
|
||||
{ code: "DJ", name: "Djibouti" },
|
||||
{ code: "DM", name: "Dominica" },
|
||||
{ code: "DO", name: "Dominican Republic" },
|
||||
{ code: "EC", name: "Ecuador" },
|
||||
{ code: "EG", name: "Egypt" },
|
||||
{ code: "SV", name: "El Salvador" },
|
||||
{ code: "GQ", name: "Equatorial Guinea" },
|
||||
{ code: "ER", name: "Eritrea" },
|
||||
{ code: "EE", name: "Estonia" },
|
||||
{ code: "SZ", name: "Eswatini" },
|
||||
{ code: "ET", name: "Ethiopia" },
|
||||
{ code: "FJ", name: "Fiji" },
|
||||
{ code: "FI", name: "Finland" },
|
||||
{ code: "FR", name: "France" },
|
||||
{ code: "GA", name: "Gabon" },
|
||||
{ code: "GM", name: "Gambia" },
|
||||
{ code: "GE", name: "Georgia" },
|
||||
{ code: "DE", name: "Germany" },
|
||||
{ code: "GH", name: "Ghana" },
|
||||
{ code: "GR", name: "Greece" },
|
||||
{ code: "GD", name: "Grenada" },
|
||||
{ code: "GT", name: "Guatemala" },
|
||||
{ code: "GN", name: "Guinea" },
|
||||
{ code: "GW", name: "Guinea-Bissau" },
|
||||
{ code: "GY", name: "Guyana" },
|
||||
{ code: "HT", name: "Haiti" },
|
||||
{ code: "HN", name: "Honduras" },
|
||||
{ code: "HU", name: "Hungary" },
|
||||
{ code: "IS", name: "Iceland" },
|
||||
{ code: "IN", name: "India" },
|
||||
{ code: "ID", name: "Indonesia" },
|
||||
{ code: "IR", name: "Iran" },
|
||||
{ code: "IQ", name: "Iraq" },
|
||||
{ code: "IE", name: "Ireland" },
|
||||
{ code: "IL", name: "Israel" },
|
||||
{ code: "IT", name: "Italy" },
|
||||
{ code: "JM", name: "Jamaica" },
|
||||
{ code: "JP", name: "Japan" },
|
||||
{ code: "JO", name: "Jordan" },
|
||||
{ code: "KZ", name: "Kazakhstan" },
|
||||
{ code: "KE", name: "Kenya" },
|
||||
{ code: "KI", name: "Kiribati" },
|
||||
{ code: "KW", name: "Kuwait" },
|
||||
{ code: "KG", name: "Kyrgyzstan" },
|
||||
{ code: "LA", name: "Laos" },
|
||||
{ code: "LV", name: "Latvia" },
|
||||
{ code: "LB", name: "Lebanon" },
|
||||
{ code: "LS", name: "Lesotho" },
|
||||
{ code: "LR", name: "Liberia" },
|
||||
{ code: "LY", name: "Libya" },
|
||||
{ code: "LI", name: "Liechtenstein" },
|
||||
{ code: "LT", name: "Lithuania" },
|
||||
{ code: "LU", name: "Luxembourg" },
|
||||
{ code: "MG", name: "Madagascar" },
|
||||
{ code: "MW", name: "Malawi" },
|
||||
{ code: "MY", name: "Malaysia" },
|
||||
{ code: "MV", name: "Maldives" },
|
||||
{ code: "ML", name: "Mali" },
|
||||
{ code: "MT", name: "Malta" },
|
||||
{ code: "MH", name: "Marshall Islands" },
|
||||
{ code: "MR", name: "Mauritania" },
|
||||
{ code: "MU", name: "Mauritius" },
|
||||
{ code: "MX", name: "Mexico" },
|
||||
{ code: "FM", name: "Micronesia" },
|
||||
{ code: "MD", name: "Moldova" },
|
||||
{ code: "MC", name: "Monaco" },
|
||||
{ code: "MN", name: "Mongolia" },
|
||||
{ code: "ME", name: "Montenegro" },
|
||||
{ code: "MA", name: "Morocco" },
|
||||
{ code: "MZ", name: "Mozambique" },
|
||||
{ code: "MM", name: "Myanmar" },
|
||||
{ code: "NA", name: "Namibia" },
|
||||
{ code: "NR", name: "Nauru" },
|
||||
{ code: "NP", name: "Nepal" },
|
||||
{ code: "NL", name: "Netherlands" },
|
||||
{ code: "NZ", name: "New Zealand" },
|
||||
{ code: "NI", name: "Nicaragua" },
|
||||
{ code: "NE", name: "Niger" },
|
||||
{ code: "NG", name: "Nigeria" },
|
||||
{ code: "KP", name: "North Korea" },
|
||||
{ code: "MK", name: "North Macedonia" },
|
||||
{ code: "NO", name: "Norway" },
|
||||
{ code: "OM", name: "Oman" },
|
||||
{ code: "PK", name: "Pakistan" },
|
||||
{ code: "PW", name: "Palau" },
|
||||
{ code: "PS", name: "Palestine" },
|
||||
{ code: "PA", name: "Panama" },
|
||||
{ code: "PG", name: "Papua New Guinea" },
|
||||
{ code: "PY", name: "Paraguay" },
|
||||
{ code: "PE", name: "Peru" },
|
||||
{ code: "PH", name: "Philippines" },
|
||||
{ code: "PL", name: "Poland" },
|
||||
{ code: "PT", name: "Portugal" },
|
||||
{ code: "QA", name: "Qatar" },
|
||||
{ code: "RO", name: "Romania" },
|
||||
{ code: "RU", name: "Russia" },
|
||||
{ code: "RW", name: "Rwanda" },
|
||||
{ code: "KN", name: "Saint Kitts and Nevis" },
|
||||
{ code: "LC", name: "Saint Lucia" },
|
||||
{ code: "VC", name: "Saint Vincent and the Grenadines" },
|
||||
{ code: "WS", name: "Samoa" },
|
||||
{ code: "SM", name: "San Marino" },
|
||||
{ code: "ST", name: "Sao Tome and Principe" },
|
||||
{ code: "SA", name: "Saudi Arabia" },
|
||||
{ code: "SN", name: "Senegal" },
|
||||
{ code: "RS", name: "Serbia" },
|
||||
{ code: "SC", name: "Seychelles" },
|
||||
{ code: "SL", name: "Sierra Leone" },
|
||||
{ code: "SG", name: "Singapore" },
|
||||
{ code: "SK", name: "Slovakia" },
|
||||
{ code: "SI", name: "Slovenia" },
|
||||
{ code: "SB", name: "Solomon Islands" },
|
||||
{ code: "SO", name: "Somalia" },
|
||||
{ code: "ZA", name: "South Africa" },
|
||||
{ code: "KR", name: "South Korea" },
|
||||
{ code: "SS", name: "South Sudan" },
|
||||
{ code: "ES", name: "Spain" },
|
||||
{ code: "LK", name: "Sri Lanka" },
|
||||
{ code: "SD", name: "Sudan" },
|
||||
{ code: "SR", name: "Suriname" },
|
||||
{ code: "SE", name: "Sweden" },
|
||||
{ code: "CH", name: "Switzerland" },
|
||||
{ code: "SY", name: "Syria" },
|
||||
{ code: "TW", name: "Taiwan" },
|
||||
{ code: "TJ", name: "Tajikistan" },
|
||||
{ code: "TZ", name: "Tanzania" },
|
||||
{ code: "TH", name: "Thailand" },
|
||||
{ code: "TL", name: "Timor-Leste" },
|
||||
{ code: "TG", name: "Togo" },
|
||||
{ code: "TO", name: "Tonga" },
|
||||
{ code: "TT", name: "Trinidad and Tobago" },
|
||||
{ code: "TN", name: "Tunisia" },
|
||||
{ code: "TR", name: "Turkey" },
|
||||
{ code: "TM", name: "Turkmenistan" },
|
||||
{ code: "TV", name: "Tuvalu" },
|
||||
{ code: "UG", name: "Uganda" },
|
||||
{ code: "UA", name: "Ukraine" },
|
||||
{ code: "AE", name: "United Arab Emirates" },
|
||||
{ code: "GB", name: "United Kingdom" },
|
||||
{ code: "US", name: "United States" },
|
||||
{ code: "UY", name: "Uruguay" },
|
||||
{ code: "UZ", name: "Uzbekistan" },
|
||||
{ code: "VU", name: "Vanuatu" },
|
||||
{ code: "VA", name: "Vatican City" },
|
||||
{ code: "VE", name: "Venezuela" },
|
||||
{ code: "VN", name: "Vietnam" },
|
||||
{ code: "YE", name: "Yemen" },
|
||||
{ code: "ZM", name: "Zambia" },
|
||||
{ code: "ZW", name: "Zimbabwe" },
|
||||
];
|
||||
Reference in New Issue
Block a user