feat(ratecard): add currency field to rate card queries and update logic

This commit is contained in:
shancds
2025-05-20 14:30:58 +05:30
parent 26b0b5780a
commit 3dd56f094c
3 changed files with 16 additions and 21 deletions

View File

@@ -29,7 +29,7 @@ public static async get(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<
( (
SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(t))), '[]'::JSON) SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(t))), '[]'::JSON)
FROM ( FROM (
SELECT id, name, team_id, created_at, updated_at SELECT id, name, team_id, currency, created_at, updated_at
FROM finance_rate_cards FROM finance_rate_cards
WHERE team_id = $1 ${searchQuery} WHERE team_id = $1 ${searchQuery}
ORDER BY ${sortField} ${sortOrder} ORDER BY ${sortField} ${sortOrder}
@@ -49,7 +49,7 @@ public static async get(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<
@HandleExceptions() @HandleExceptions()
public static async getById(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> { public static async getById(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = ` const q = `
SELECT id, name, team_id, created_at, updated_at SELECT id, name, team_id, currency, created_at, updated_at
FROM finance_rate_cards FROM finance_rate_cards
WHERE id = $1 AND team_id = $2; WHERE id = $1 AND team_id = $2;
`; `;
@@ -62,11 +62,11 @@ public static async get(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<
public static async update(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> { public static async update(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = ` const q = `
UPDATE finance_rate_cards UPDATE finance_rate_cards
SET name = $3, updated_at = NOW() SET name = $3, currency = $4, updated_at = NOW()
WHERE id = $1 AND team_id = $2 WHERE id = $1 AND team_id = $2
RETURNING id, name, team_id, created_at, updated_at; RETURNING id, name, team_id, currency, created_at, updated_at;
`; `;
const result = await db.query(q, [req.params.id, req.user?.team_id || null, req.body.name]); const result = await db.query(q, [req.params.id, req.user?.team_id || null, req.body.name, req.body.currency]);
const [data] = result.rows; const [data] = result.rows;
return res.status(200).send(new ServerResponse(true, data)); return res.status(200).send(new ServerResponse(true, data));
} }

View File

@@ -87,6 +87,7 @@ export const updateRateCard = createAsyncThunk(
async ({ id, body }: { id: string; body: RatecardType }, { rejectWithValue }) => { async ({ id, body }: { id: string; body: RatecardType }, { rejectWithValue }) => {
try { try {
const response = await rateCardApiService.updateRateCard(id, body); const response = await rateCardApiService.updateRateCard(id, body);
console.log('response', response);
return response.body; return response.body;
} catch (error) { } catch (error) {
logger.error('Update RateCard', error); logger.error('Update RateCard', error);

View File

@@ -3,14 +3,12 @@ import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useAppSelector } from '../../../hooks/useAppSelector'; import { useAppSelector } from '../../../hooks/useAppSelector';
import { useAppDispatch } from '../../../hooks/useAppDispatch'; import { useAppDispatch } from '../../../hooks/useAppDispatch';
import { fetchData } from '../../../utils/fetchData';
import { fetchRateCardById, fetchRateCards, toggleRatecardDrawer, updateRateCard } from '../finance-slice'; import { fetchRateCardById, fetchRateCards, toggleRatecardDrawer, updateRateCard } from '../finance-slice';
import { RatecardType, IJobType } from '@/types/project/ratecard.types'; import { RatecardType, IJobType } from '@/types/project/ratecard.types';
import { IJobTitlesViewModel } from '@/types/job.types'; import { IJobTitlesViewModel } from '@/types/job.types';
import { DEFAULT_PAGE_SIZE } from '@/shared/constants'; import { DEFAULT_PAGE_SIZE } from '@/shared/constants';
import { jobTitlesApiService } from '@/api/settings/job-titles/job-titles.api.service'; import { jobTitlesApiService } from '@/api/settings/job-titles/job-titles.api.service';
import { DeleteOutlined } from '@ant-design/icons'; import { DeleteOutlined } from '@ant-design/icons';
import { rateCardApiService } from '@/api/settings/rate-cards/rate-cards.api.service';
interface PaginationType { interface PaginationType {
current: number; current: number;
@@ -36,20 +34,16 @@ const RatecardDrawer = ({
const { t } = useTranslation('settings/ratecard-settings'); const { t } = useTranslation('settings/ratecard-settings');
// get drawer state from client reducer // get drawer state from client reducer
const drawerLoading = useAppSelector(state => state.financeReducer.drawerLoading); const drawerLoading = useAppSelector(state => state.financeReducer.isFinanceDrawerloading);
const drawerRatecard = useAppSelector(state => state.financeReducer.drawerRatecard); const drawerRatecard = useAppSelector(state => state.financeReducer.drawerRatecard);
const isDrawerOpen = useAppSelector( const isDrawerOpen = useAppSelector(
(state) => state.financeReducer.isRatecardDrawerOpen (state) => state.financeReducer.isRatecardDrawerOpen
); );
// get currently using currency from finance reducer
const cur = useAppSelector(
(state) => state.financeReducer.currency
).toUpperCase();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [isAddingRole, setIsAddingRole] = useState(false); const [isAddingRole, setIsAddingRole] = useState(false);
const [selectedJobTitleId, setSelectedJobTitleId] = useState<string | undefined>(undefined); const [selectedJobTitleId, setSelectedJobTitleId] = useState<string | undefined>(undefined);
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [currency, setCurrency] = useState(cur); const [currency, setCurrency] = useState('LKR');
const [name, setName] = useState<string>('Untitled Rate Card'); const [name, setName] = useState<string>('Untitled Rate Card');
const [jobTitles, setJobTitles] = useState<IJobTitlesViewModel>({}); const [jobTitles, setJobTitles] = useState<IJobTitlesViewModel>({});
const [pagination, setPagination] = useState<PaginationType>({ const [pagination, setPagination] = useState<PaginationType>({
@@ -99,7 +93,7 @@ const RatecardDrawer = ({
if (type === 'update' && drawerRatecard) { if (type === 'update' && drawerRatecard) {
setRoles(drawerRatecard.jobRolesList || []); setRoles(drawerRatecard.jobRolesList || []);
setName(drawerRatecard.name || ''); setName(drawerRatecard.name || '');
setCurrency(drawerRatecard.currency || cur); setCurrency(drawerRatecard.currency || 'LKR');
} }
}, [drawerRatecard, type]); }, [drawerRatecard, type]);
@@ -119,11 +113,11 @@ const RatecardDrawer = ({
const jobTitle = jobTitles.data?.find(jt => jt.id === jobTitleId); const jobTitle = jobTitles.data?.find(jt => jt.id === jobTitleId);
if (jobTitle) { if (jobTitle) {
const newRole = { const newRole = {
jobId: jobTitleId, rate_card_id: jobTitleId,
jobTitle: jobTitle.name || 'New Role', jobTitle: jobTitle.name || 'New Role',
ratePerHour: 0, ratePerHour: 0,
}; };
setRoles([...roles, newRole]); // setRoles([...roles, newRole]);
} }
setIsAddingRole(false); setIsAddingRole(false);
setSelectedJobTitleId(undefined); setSelectedJobTitleId(undefined);
@@ -239,13 +233,13 @@ const RatecardDrawer = ({
<Flex gap={8} align="center"> <Flex gap={8} align="center">
<Typography.Text>{t('currency')}</Typography.Text> <Typography.Text>{t('currency')}</Typography.Text>
<Select <Select
value={currency.toLowerCase()} value={currency}
options={[ options={[
{ value: 'lkr', label: 'LKR' }, { value: 'LKR', label: 'LKR' },
{ value: 'usd', label: 'USD' }, { value: 'USD', label: 'USD' },
{ value: 'inr', label: 'INR' }, { value: 'INR', label: 'INR' },
]} ]}
onChange={(value) => setCurrency(value.toUpperCase())} onChange={(value) => setCurrency(value)}
/> />
</Flex> </Flex>
</Flex> </Flex>