feat(project-currency): implement project-specific currency support
- Added a currency column to the projects table to allow different projects to use different currencies. - Updated existing projects to default to 'USD' if no currency is set. - Enhanced project finance controller to handle currency retrieval and updates. - Introduced API endpoints for updating project currency with validation. - Updated frontend components to display and manage project currency effectively.
This commit is contained in:
@@ -7,6 +7,7 @@ import { useAppDispatch } from '@/hooks/useAppDispatch';
|
||||
import { useAppSelector } from '@/hooks/useAppSelector';
|
||||
import { fetchProjectFinances, setActiveTab, setActiveGroup } from '@/features/projects/finance/project-finance.slice';
|
||||
import { changeCurrency, toggleImportRatecardsDrawer } from '@/features/finance/finance-slice';
|
||||
import { updateProjectCurrency } from '@/features/project/project.slice';
|
||||
import { projectFinanceApiService } from '@/api/project-finance-ratecard/project-finance.api.service';
|
||||
import { RootState } from '@/app/store';
|
||||
import FinanceTableWrapper from './finance-tab/finance-table/finance-table-wrapper';
|
||||
@@ -14,14 +15,16 @@ import RatecardTable from './ratecard-tab/reatecard-table/ratecard-table';
|
||||
import ImportRatecardsDrawer from '@/features/finance/ratecard-drawer/import-ratecards-drawer';
|
||||
import { useAuthService } from '@/hooks/useAuth';
|
||||
import { hasFinanceEditPermission } from '@/utils/finance-permissions';
|
||||
import { CURRENCY_OPTIONS, DEFAULT_CURRENCY } from '@/shared/constants/currencies';
|
||||
|
||||
const ProjectViewFinance = () => {
|
||||
const { projectId } = useParams<{ projectId: string }>();
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation('project-view-finance');
|
||||
const [exporting, setExporting] = useState(false);
|
||||
const [updatingCurrency, setUpdatingCurrency] = useState(false);
|
||||
|
||||
const { activeTab, activeGroup, loading, taskGroups } = useAppSelector((state: RootState) => state.projectFinances);
|
||||
const { activeTab, activeGroup, loading, taskGroups, project: financeProject } = useAppSelector((state: RootState) => state.projectFinances);
|
||||
const { refreshTimestamp, project } = useAppSelector((state: RootState) => state.projectReducer);
|
||||
const phaseList = useAppSelector((state) => state.phaseReducer.phaseList);
|
||||
|
||||
@@ -30,6 +33,12 @@ const ProjectViewFinance = () => {
|
||||
const currentSession = auth.getCurrentSession();
|
||||
const hasEditPermission = hasFinanceEditPermission(currentSession, project);
|
||||
|
||||
// Get project-specific currency from finance API response, fallback to project reducer, then default
|
||||
const projectCurrency = (financeProject?.currency || project?.currency || DEFAULT_CURRENCY).toLowerCase();
|
||||
|
||||
// Show loading state for currency selector until finance data is loaded
|
||||
const currencyLoading = loading || updatingCurrency || !financeProject;
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId) {
|
||||
dispatch(fetchProjectFinances({ projectId, groupBy: activeGroup }));
|
||||
@@ -71,6 +80,30 @@ const ProjectViewFinance = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCurrencyChange = async (currency: string) => {
|
||||
if (!projectId || !hasEditPermission) {
|
||||
message.error('You do not have permission to change the project currency');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setUpdatingCurrency(true);
|
||||
const upperCaseCurrency = currency.toUpperCase();
|
||||
await projectFinanceApiService.updateProjectCurrency(projectId, upperCaseCurrency);
|
||||
|
||||
// Update both global currency state and project-specific currency
|
||||
dispatch(changeCurrency(currency));
|
||||
dispatch(updateProjectCurrency(upperCaseCurrency));
|
||||
|
||||
message.success('Project currency updated successfully');
|
||||
} catch (error) {
|
||||
console.error('Currency update failed:', error);
|
||||
message.error('Failed to update project currency');
|
||||
} finally {
|
||||
setUpdatingCurrency(false);
|
||||
}
|
||||
};
|
||||
|
||||
const groupDropdownMenuItems = [
|
||||
{ key: 'status', value: 'status', label: t('statusText') },
|
||||
{ key: 'priority', value: 'priority', label: t('priorityText') },
|
||||
@@ -130,13 +163,11 @@ const ProjectViewFinance = () => {
|
||||
<Flex gap={8} align="center">
|
||||
<Typography.Text>{t('currencyText')}</Typography.Text>
|
||||
<Select
|
||||
defaultValue={'lkr'}
|
||||
options={[
|
||||
{ value: 'lkr', label: 'LKR' },
|
||||
{ value: 'usd', label: 'USD' },
|
||||
{ value: 'inr', label: 'INR' },
|
||||
]}
|
||||
onChange={(value) => dispatch(changeCurrency(value))}
|
||||
value={projectCurrency}
|
||||
loading={currencyLoading}
|
||||
disabled={!hasEditPermission}
|
||||
options={CURRENCY_OPTIONS}
|
||||
onChange={handleCurrencyChange}
|
||||
/>
|
||||
</Flex>
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user