feat: Add Ratecard management functionality with localization support
This commit is contained in:
@@ -0,0 +1,163 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "c2669c5f-a019-445b-b703-b941bbefdab7",
|
||||||
|
"type": "low",
|
||||||
|
"name": "Low",
|
||||||
|
"color_code": "#c2e4d0",
|
||||||
|
"color_code_dark": "#46d980",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "4be5ef5c-1234-4247-b159-6d8df2b37d04",
|
||||||
|
"task": "Testing and QA",
|
||||||
|
"isBillable": false,
|
||||||
|
"hours": 180,
|
||||||
|
"cost": 18000,
|
||||||
|
"fixedCost": 2500,
|
||||||
|
"totalBudget": 20000,
|
||||||
|
"totalActual": 21000,
|
||||||
|
"variance": -1000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "6",
|
||||||
|
"name": "Eve Adams",
|
||||||
|
"jobId": "J006",
|
||||||
|
"jobRole": "QA Engineer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6be5ef5c-1234-4247-b159-6d8df2b37d06",
|
||||||
|
"task": "Project Documentation",
|
||||||
|
"isBillable": false,
|
||||||
|
"hours": 100,
|
||||||
|
"cost": 10000,
|
||||||
|
"fixedCost": 1000,
|
||||||
|
"totalBudget": 12000,
|
||||||
|
"totalActual": 12500,
|
||||||
|
"variance": -500,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "8",
|
||||||
|
"name": "Grace Lee",
|
||||||
|
"jobId": "J008",
|
||||||
|
"jobRole": "Technical Writer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d3f9c5f1-b019-445b-b703-b941bbefdab8",
|
||||||
|
"type": "medium",
|
||||||
|
"name": "Medium",
|
||||||
|
"color_code": "#f9e3b1",
|
||||||
|
"color_code_dark": "#ffc227",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "1be5ef5c-1234-4247-b159-6d8df2b37d01",
|
||||||
|
"task": "UI Design",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 120,
|
||||||
|
"cost": 12000,
|
||||||
|
"fixedCost": 1500,
|
||||||
|
"totalBudget": 14000,
|
||||||
|
"totalActual": 13500,
|
||||||
|
"variance": 500,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "1",
|
||||||
|
"name": "John Doe",
|
||||||
|
"jobId": "J001",
|
||||||
|
"jobRole": "UI/UX Designer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"memberId": "2",
|
||||||
|
"name": "Jane Smith",
|
||||||
|
"jobId": "J002",
|
||||||
|
"jobRole": "Frontend Developer",
|
||||||
|
"hourlyRate": 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2be5ef5c-1234-4247-b159-6d8df2b37d02",
|
||||||
|
"task": "API Integration",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 200,
|
||||||
|
"cost": 20000,
|
||||||
|
"fixedCost": 3000,
|
||||||
|
"totalBudget": 25000,
|
||||||
|
"totalActual": 26000,
|
||||||
|
"variance": -1000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "3",
|
||||||
|
"name": "Alice Johnson",
|
||||||
|
"jobId": "J003",
|
||||||
|
"jobRole": "Backend Developer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e3f9c5f1-b019-445b-b703-b941bbefdab9",
|
||||||
|
"type": "high",
|
||||||
|
"name": "High",
|
||||||
|
"color_code": "#f6bfc0",
|
||||||
|
"color_code_dark": "#ff4141",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "5be5ef5c-1234-4247-b159-6d8df2b37d05",
|
||||||
|
"task": "Database Migration",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 250,
|
||||||
|
"cost": 37500,
|
||||||
|
"fixedCost": 4000,
|
||||||
|
"totalBudget": 42000,
|
||||||
|
"totalActual": 41000,
|
||||||
|
"variance": 1000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "7",
|
||||||
|
"name": "Frank Harris",
|
||||||
|
"jobId": "J007",
|
||||||
|
"jobRole": "Database Administrator",
|
||||||
|
"hourlyRate": 150
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3be5ef5c-1234-4247-b159-6d8df2b37d03",
|
||||||
|
"task": "Performance Optimization",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 300,
|
||||||
|
"cost": 45000,
|
||||||
|
"fixedCost": 5000,
|
||||||
|
"totalBudget": 50000,
|
||||||
|
"totalActual": 47000,
|
||||||
|
"variance": 3000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "4",
|
||||||
|
"name": "Bob Brown",
|
||||||
|
"jobId": "J004",
|
||||||
|
"jobRole": "Performance Engineer",
|
||||||
|
"hourlyRate": 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"memberId": "5",
|
||||||
|
"name": "Charlie Davis",
|
||||||
|
"jobId": "J005",
|
||||||
|
"jobRole": "Full Stack Developer",
|
||||||
|
"hourlyRate": 130
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "c2669c5f-a019-445b-b703-b941bbefdab7",
|
||||||
|
"type": "todo",
|
||||||
|
"name": "To Do",
|
||||||
|
"color_code": "#d8d7d8",
|
||||||
|
"color_code_dark": "#989898",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "1be5ef5c-1234-4247-b159-6d8df2b37d01",
|
||||||
|
"task": "UI Design",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 120,
|
||||||
|
"cost": 12000,
|
||||||
|
"fixedCost": 1500,
|
||||||
|
"totalBudget": 14000,
|
||||||
|
"totalActual": 13500,
|
||||||
|
"variance": 500,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "1",
|
||||||
|
"name": "John Doe",
|
||||||
|
"jobId": "J001",
|
||||||
|
"jobRole": "UI/UX Designer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"memberId": "2",
|
||||||
|
"name": "Jane Smith",
|
||||||
|
"jobId": "J002",
|
||||||
|
"jobRole": "Frontend Developer",
|
||||||
|
"hourlyRate": 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2be5ef5c-1234-4247-b159-6d8df2b37d02",
|
||||||
|
"task": "API Integration",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 200,
|
||||||
|
"cost": 20000,
|
||||||
|
"fixedCost": 3000,
|
||||||
|
"totalBudget": 25000,
|
||||||
|
"totalActual": 26000,
|
||||||
|
"variance": -1000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "3",
|
||||||
|
"name": "Alice Johnson",
|
||||||
|
"jobId": "J003",
|
||||||
|
"jobRole": "Backend Developer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d3f9c5f1-b019-445b-b703-b941bbefdab8",
|
||||||
|
"type": "doing",
|
||||||
|
"name": "In Progress",
|
||||||
|
"color_code": "#c0d5f6",
|
||||||
|
"color_code_dark": "#4190ff",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "3be5ef5c-1234-4247-b159-6d8df2b37d03",
|
||||||
|
"task": "Performance Optimization",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 300,
|
||||||
|
"cost": 45000,
|
||||||
|
"fixedCost": 5000,
|
||||||
|
"totalBudget": 50000,
|
||||||
|
"totalActual": 47000,
|
||||||
|
"variance": 3000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "4",
|
||||||
|
"name": "Bob Brown",
|
||||||
|
"jobId": "J004",
|
||||||
|
"jobRole": "Performance Engineer",
|
||||||
|
"hourlyRate": 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"memberId": "5",
|
||||||
|
"name": "Charlie Davis",
|
||||||
|
"jobId": "J005",
|
||||||
|
"jobRole": "Full Stack Developer",
|
||||||
|
"hourlyRate": 130
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4be5ef5c-1234-4247-b159-6d8df2b37d04",
|
||||||
|
"task": "Testing and QA",
|
||||||
|
"isBillable": false,
|
||||||
|
"hours": 180,
|
||||||
|
"cost": 18000,
|
||||||
|
"fixedCost": 2500,
|
||||||
|
"totalBudget": 20000,
|
||||||
|
"totalActual": 21000,
|
||||||
|
"variance": -1000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "6",
|
||||||
|
"name": "Eve Adams",
|
||||||
|
"jobId": "J006",
|
||||||
|
"jobRole": "QA Engineer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e3f9c5f1-b019-445b-b703-b941bbefdab9",
|
||||||
|
"type": "done",
|
||||||
|
"name": "Done",
|
||||||
|
"color_code": "#c2e4d0",
|
||||||
|
"color_code_dark": "#46d980",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "5be5ef5c-1234-4247-b159-6d8df2b37d05",
|
||||||
|
"task": "Database Migration",
|
||||||
|
"isBillable": true,
|
||||||
|
"hours": 250,
|
||||||
|
"cost": 37500,
|
||||||
|
"fixedCost": 4000,
|
||||||
|
"totalBudget": 42000,
|
||||||
|
"totalActual": 41000,
|
||||||
|
"variance": 1000,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "7",
|
||||||
|
"name": "Frank Harris",
|
||||||
|
"jobId": "J007",
|
||||||
|
"jobRole": "Database Administrator",
|
||||||
|
"hourlyRate": 150
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6be5ef5c-1234-4247-b159-6d8df2b37d06",
|
||||||
|
"task": "Project Documentation",
|
||||||
|
"isBillable": false,
|
||||||
|
"hours": 100,
|
||||||
|
"cost": 10000,
|
||||||
|
"fixedCost": 1000,
|
||||||
|
"totalBudget": 12000,
|
||||||
|
"totalActual": 12500,
|
||||||
|
"variance": -500,
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"memberId": "8",
|
||||||
|
"name": "Grace Lee",
|
||||||
|
"jobId": "J008",
|
||||||
|
"jobRole": "Technical Writer",
|
||||||
|
"hourlyRate": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"ratecardId": "RC001",
|
||||||
|
"ratecardName": "Rate Card 1",
|
||||||
|
"jobRolesList": [
|
||||||
|
{
|
||||||
|
"jobId": "J001",
|
||||||
|
"jobTitle": "Project Manager",
|
||||||
|
"ratePerHour": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jobId": "J002",
|
||||||
|
"jobTitle": "Senior Software Engineer",
|
||||||
|
"ratePerHour": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jobId": "J003",
|
||||||
|
"jobTitle": "Junior Software Engineer",
|
||||||
|
"ratePerHour": 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jobId": "J004",
|
||||||
|
"jobTitle": "UI/UX Designer",
|
||||||
|
"ratePerHour": 50
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"createdDate": "2024-12-01T00:00:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ratecardId": "RC002",
|
||||||
|
"ratecardName": "Rate Card 2",
|
||||||
|
"jobRolesList": [
|
||||||
|
{
|
||||||
|
"jobId": "J001",
|
||||||
|
"jobTitle": "Project Manager",
|
||||||
|
"ratePerHour": 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jobId": "J002",
|
||||||
|
"jobTitle": "Senior Software Engineer",
|
||||||
|
"ratePerHour": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jobId": "J003",
|
||||||
|
"jobTitle": "Junior Software Engineer",
|
||||||
|
"ratePerHour": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"createdDate": "2024-12-15T00:00:00.000Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"nameColumn": "Name",
|
||||||
|
"createdColumn": "Created",
|
||||||
|
"noProjectsAvailable": "No projects available",
|
||||||
|
"deleteConfirmationTitle": "Are you sure?",
|
||||||
|
"deleteConfirmationOk": "Yes",
|
||||||
|
"deleteConfirmationCancel": "Cancel",
|
||||||
|
"searchPlaceholder": "Search by name",
|
||||||
|
"createRatecard": "Create Rate Card",
|
||||||
|
|
||||||
|
"jobTitleColumn": "Job title",
|
||||||
|
"ratePerHourColumn": "Rate per hour",
|
||||||
|
"saveButton": "Save",
|
||||||
|
"addRoleButton": "+ Add Role",
|
||||||
|
"createRatecardSuccessMessage": "Create Rate Card success!",
|
||||||
|
"createRatecardErrorMessage": "Create Rate Card failed!",
|
||||||
|
"updateRatecardSuccessMessage": "Update Rate Card success!",
|
||||||
|
"updateRatecardErrorMessage": "Update Rate Card failed!",
|
||||||
|
"currency": "Currency"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"nameColumn": "Nombre",
|
||||||
|
"createdColumn": "Creado",
|
||||||
|
"noProjectsAvailable": "No hay proyectos disponibles",
|
||||||
|
"deleteConfirmationTitle": "¿Estás seguro?",
|
||||||
|
"deleteConfirmationOk": "Sí",
|
||||||
|
"deleteConfirmationCancel": "Cancelar",
|
||||||
|
"searchPlaceholder": "Buscar por nombre",
|
||||||
|
"createRatecard": "Crear Tarifa",
|
||||||
|
|
||||||
|
"jobTitleColumn": "Puesto de trabajo",
|
||||||
|
"ratePerHourColumn": "Tarifa por hora",
|
||||||
|
"saveButton": "Guardar",
|
||||||
|
"addRoleButton": "+ Agregar Rol",
|
||||||
|
"createRatecardSuccessMessage": "¡Tarifa creada con éxito!",
|
||||||
|
"createRatecardErrorMessage": "¡Error al crear la tarifa!",
|
||||||
|
"updateRatecardSuccessMessage": "¡Tarifa actualizada con éxito!",
|
||||||
|
"updateRatecardErrorMessage": "¡Error al actualizar la tarifa!",
|
||||||
|
"currency": "Moneda"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"nameColumn": "Nome",
|
||||||
|
"createdColumn": "Criado",
|
||||||
|
"noProjectsAvailable": "Nenhum projeto disponível",
|
||||||
|
"deleteConfirmationTitle": "Tem certeza?",
|
||||||
|
"deleteConfirmationOk": "Sim",
|
||||||
|
"deleteConfirmationCancel": "Cancelar",
|
||||||
|
"searchPlaceholder": "Pesquisar por nome",
|
||||||
|
"createRatecard": "Criar Tabela de Preços",
|
||||||
|
|
||||||
|
"jobTitleColumn": "Cargo",
|
||||||
|
"ratePerHourColumn": "Taxa por hora",
|
||||||
|
"saveButton": "Salvar",
|
||||||
|
"addRoleButton": "+ Adicionar Função",
|
||||||
|
"createRatecardSuccessMessage": "Tabela de Preços criada com sucesso!",
|
||||||
|
"createRatecardErrorMessage": "Falha ao criar Tabela de Preços!",
|
||||||
|
"updateRatecardSuccessMessage": "Tabela de Preços atualizada com sucesso!",
|
||||||
|
"updateRatecardErrorMessage": "Falha ao atualizar Tabela de Preços!",
|
||||||
|
"currency": "Moeda"
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ const RatecardDrawer = ({
|
|||||||
const [roles, setRoles] = useState<JobType[]>([]);
|
const [roles, setRoles] = useState<JobType[]>([]);
|
||||||
|
|
||||||
// localization
|
// localization
|
||||||
const { t } = useTranslation('ratecard-settings');
|
const { t } = useTranslation('settings/ratecard-settings');
|
||||||
|
|
||||||
// get drawer state from client reducer
|
// get drawer state from client reducer
|
||||||
const isDrawerOpen = useAppSelector(
|
const isDrawerOpen = useAppSelector(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
BankOutlined,
|
BankOutlined,
|
||||||
|
DollarCircleOutlined,
|
||||||
FileZipOutlined,
|
FileZipOutlined,
|
||||||
GlobalOutlined,
|
GlobalOutlined,
|
||||||
GroupOutlined,
|
GroupOutlined,
|
||||||
@@ -25,6 +26,7 @@ import TeamMembersSettings from '@/pages/settings/team-members/team-members-sett
|
|||||||
import TeamsSettings from '../../pages/settings/teams/teams-settings';
|
import TeamsSettings from '../../pages/settings/teams/teams-settings';
|
||||||
import ChangePassword from '@/pages/settings/change-password/change-password';
|
import ChangePassword from '@/pages/settings/change-password/change-password';
|
||||||
import LanguageAndRegionSettings from '@/pages/settings/language-and-region/language-and-region-settings';
|
import LanguageAndRegionSettings from '@/pages/settings/language-and-region/language-and-region-settings';
|
||||||
|
import RatecardSettings from '@/pages/settings/ratecard/ratecard-settings';
|
||||||
|
|
||||||
// type of menu item in settings sidebar
|
// type of menu item in settings sidebar
|
||||||
type SettingMenuItems = {
|
type SettingMenuItems = {
|
||||||
@@ -123,6 +125,13 @@ export const settingsItems: SettingMenuItems[] = [
|
|||||||
element: React.createElement(TeamMembersSettings),
|
element: React.createElement(TeamMembersSettings),
|
||||||
adminOnly: true,
|
adminOnly: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'ratecard',
|
||||||
|
name: 'Ratecard',
|
||||||
|
endpoint: 'ratecard',
|
||||||
|
icon: React.createElement(DollarCircleOutlined),
|
||||||
|
element: React.createElement(RatecardSettings),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'teams',
|
key: 'teams',
|
||||||
name: 'teams',
|
name: 'teams',
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
import {
|
||||||
|
DeleteOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
ExclamationCircleFilled,
|
||||||
|
SearchOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Flex,
|
||||||
|
Input,
|
||||||
|
Popconfirm,
|
||||||
|
Table,
|
||||||
|
TableProps,
|
||||||
|
Tooltip,
|
||||||
|
Typography,
|
||||||
|
} from 'antd';
|
||||||
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { colors } from '../../../styles/colors';
|
||||||
|
import { useAppDispatch } from '../../../hooks/useAppDispatch';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useDocumentTitle } from '../../../hooks/useDoumentTItle';
|
||||||
|
import { durationDateFormat } from '../../../utils/durationDateFormat';
|
||||||
|
import { toggleRatecardDrawer } from '../../../features/finance/finance-slice';
|
||||||
|
import RatecardDrawer from '../../../features/finance/ratecard-drawer/ratecard-drawer';
|
||||||
|
import { fetchData } from '../../../utils/fetchData';
|
||||||
|
import { RatecardType } from '@/types/project/ratecard.types';
|
||||||
|
|
||||||
|
const RatecardSettings = () => {
|
||||||
|
const [ratecardsList, setRatecardsList] = useState<RatecardType[]>([]);
|
||||||
|
// get currently selected ratecard id
|
||||||
|
const [selectedRatecardId, setSelectedRatecardId] = useState<string | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
const [ratecardDrawerType, setRatecardDrawerType] = useState<
|
||||||
|
'create' | 'update'
|
||||||
|
>('create');
|
||||||
|
|
||||||
|
// localization
|
||||||
|
const { t } = useTranslation('/settings/ratecard-settings');
|
||||||
|
|
||||||
|
useDocumentTitle('Manage Rate Cards');
|
||||||
|
|
||||||
|
// Fetch rate cards data
|
||||||
|
useEffect(() => {
|
||||||
|
fetchData('/finance-mock-data/ratecards-data.json', setRatecardsList);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
// this is for get the current string that type on search bar
|
||||||
|
const [searchQuery, setSearchQuery] = useState<string>('');
|
||||||
|
|
||||||
|
// used useMemo hook for re render the list when searching
|
||||||
|
const filteredRatecardsData = useMemo(() => {
|
||||||
|
return ratecardsList.filter((item) =>
|
||||||
|
item.ratecardName.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
}, [ratecardsList, searchQuery]);
|
||||||
|
|
||||||
|
// function to create ratecard
|
||||||
|
const onRatecardCreate = () => {
|
||||||
|
setRatecardDrawerType('create');
|
||||||
|
dispatch(toggleRatecardDrawer());
|
||||||
|
};
|
||||||
|
|
||||||
|
// function to update a ratecard
|
||||||
|
const onRatecardUpdate = (id: string) => {
|
||||||
|
setRatecardDrawerType('update');
|
||||||
|
setSelectedRatecardId(id);
|
||||||
|
dispatch(toggleRatecardDrawer());
|
||||||
|
};
|
||||||
|
|
||||||
|
// table columns
|
||||||
|
const columns: TableProps['columns'] = [
|
||||||
|
{
|
||||||
|
key: 'rateName',
|
||||||
|
title: t('nameColumn'),
|
||||||
|
onCell: (record) => ({
|
||||||
|
onClick: () => {
|
||||||
|
setSelectedRatecardId(record.ratecardId);
|
||||||
|
// dispatch(toggleUpdateRateDrawer());
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
render: (record) => (
|
||||||
|
<Typography.Text className="group-hover:text-[#1890ff]">
|
||||||
|
{record.ratecardName}
|
||||||
|
</Typography.Text>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'created',
|
||||||
|
title: t('createdColumn'),
|
||||||
|
onCell: (record) => ({
|
||||||
|
onClick: () => {
|
||||||
|
setSelectedRatecardId(record.ratecardId);
|
||||||
|
// dispatch(toggleUpdateRateDrawer());
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
render: (record) => (
|
||||||
|
<Typography.Text>
|
||||||
|
{durationDateFormat(record.createdDate)}
|
||||||
|
</Typography.Text>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'actionBtns',
|
||||||
|
width: 80,
|
||||||
|
render: (record) => (
|
||||||
|
<Flex
|
||||||
|
gap={8}
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
className="hidden group-hover:block"
|
||||||
|
>
|
||||||
|
<Tooltip title="Edit">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
onRatecardUpdate(record.ratecardId);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Popconfirm
|
||||||
|
title={t('deleteConfirmationTitle')}
|
||||||
|
icon={
|
||||||
|
<ExclamationCircleFilled
|
||||||
|
style={{ color: colors.vibrantOrange }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
okText={t('deleteConfirmationOk')}
|
||||||
|
cancelText={t('deleteConfirmationCancel')}
|
||||||
|
// onConfirm={() => dispatch(deleteRatecard(record.ratecardId))}
|
||||||
|
>
|
||||||
|
<Tooltip title="Delete">
|
||||||
|
<Button
|
||||||
|
shape="default"
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
size="small"
|
||||||
|
style={{ marginInlineStart: 8 }}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Popconfirm>
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
title={
|
||||||
|
<Flex justify="flex-end">
|
||||||
|
<Flex
|
||||||
|
gap={8}
|
||||||
|
align="center"
|
||||||
|
justify="flex-end"
|
||||||
|
style={{ width: '100%', maxWidth: 400 }}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.currentTarget.value)}
|
||||||
|
placeholder={t('searchPlaceholder')}
|
||||||
|
style={{ maxWidth: 232 }}
|
||||||
|
suffix={<SearchOutlined />}
|
||||||
|
/>
|
||||||
|
<Button type="primary" onClick={onRatecardCreate}>
|
||||||
|
{t('createRatecard')}
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
className="custom-two-colors-row-table"
|
||||||
|
dataSource={filteredRatecardsData}
|
||||||
|
columns={columns}
|
||||||
|
rowKey={(record) => record.rateId}
|
||||||
|
pagination={{
|
||||||
|
showSizeChanger: true,
|
||||||
|
defaultPageSize: 20,
|
||||||
|
pageSizeOptions: ['5', '10', '15', '20', '50', '100'],
|
||||||
|
size: 'small',
|
||||||
|
}}
|
||||||
|
onRow={(record) => {
|
||||||
|
return {
|
||||||
|
className: 'group',
|
||||||
|
style: {
|
||||||
|
cursor: 'pointer',
|
||||||
|
height: 36,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* rate drawers */}
|
||||||
|
<RatecardDrawer
|
||||||
|
type={ratecardDrawerType}
|
||||||
|
ratecardId={selectedRatecardId || ''}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RatecardSettings;
|
||||||
Reference in New Issue
Block a user