omnipay-savings-sdk
Version:
Omnipay Savings SDK
260 lines (228 loc) • 7.83 kB
text/typescript
import {
FrequencyType,
getFrequencyEnum,
DeductionNameType,
TypesOfDeductionType,
TypesOfDeductionFrequencyType,
} from '../../../utils';
import {SavingsDetailType} from '../../../utils/types';
import {UpdateSavingsParams} from '../../../services/types';
// Common types and constants
export const typesOfDeduction: TypesOfDeductionType[] = [
{
name: 'Percentage',
id: '0',
},
{
name: 'Flat rate',
id: '1',
},
];
export const frequencies: TypesOfDeductionFrequencyType[] = [
{
name: 'One-time',
id: '0',
},
{
name: 'Reoccurring',
id: '1',
},
];
// Helper function to convert frequency ID to FrequencyType
export const getFrequencyTypeFromId = (frequencyId: number): FrequencyType => {
switch (frequencyId) {
case 1:
return 'Daily';
case 2:
return 'Weekly';
case 3:
return 'Monthly';
case 4:
return 'Save as you collect';
default:
return '' as FrequencyType;
}
};
// Helper function to check if there are actual changes between new data and existing data
export const checkForChanges = (newData: UpdateSavingsParams, existingData: SavingsDetailType): boolean => {
// Helper function to format dates for comparison
const formatDateForComparison = (dateString: string) => {
if (!dateString) {return '';}
const date = new Date(dateString);
return date.toISOString().split('T')[0]; // YYYY-MM-DD format
};
// Check basic fields
if (newData.accountName !== existingData.accountName) {return true;}
if (newData.savingTarget !== existingData.savingTarget * 100) {return true;}
if (newData.narration !== (existingData.narration || '')) {return true;}
if (newData.autoSave !== existingData.autoSave) {return true;}
if (newData.isInterestDisabled !== existingData.isInterestDisabled) {return true;}
// Check color change (case-insensitive)
const newColor = (newData.savingsPlanColor || '').toLowerCase();
const existingColor = (existingData.savingsPlanColor || '').toLowerCase();
if (newColor !== existingColor) {return true;}
// Check frequency if auto-save is enabled
if (newData.autoSave) {
if (newData.frequency !== existingData.savingsFrequencyId) {return true;}
// Check periodic amount for non-SaveAsYouCollect frequencies
if (newData.frequency !== 4 && newData.periodicSavingsAmount) {
if (newData.periodicSavingsAmount !== existingData.periodicSavingsAmount * 100) {return true;}
}
// Check dates
if (newData.startDate && existingData.startDate && formatDateForComparison(newData.startDate) !== formatDateForComparison(existingData.startDate)) {return true;}
if (newData.endDate && existingData.endDate && formatDateForComparison(newData.endDate) !== formatDateForComparison(existingData.endDate)) {return true;}
}
return false; // No changes detected
};
// Helper function to ensure the color exists in available options
export const getValidSavingsColor = (color?: string, editMode?: boolean, availableColors?: string[]) => {
if (!color || !editMode) {return '';}
// Import savingsOptionsColors here to avoid circular dependency
const {savingsOptionsColors} = require('../../../utils');
const colorsToCheck = availableColors || savingsOptionsColors;
// Check if the color exists in the available options (case-insensitive)
const foundColor = colorsToCheck.find((option: string) =>
option.toLowerCase() === color.toLowerCase()
);
if (foundColor) {
return foundColor;
}
// If not found, use the first option as fallback
return colorsToCheck[0]; // Fallback to first available color
};
// Common validation errors type
export interface ValidationError {
field: string;
message: string;
}
// Base validation for common fields
export const validateCommonFields = (
name: string,
amount: string,
savingsColor: string
): ValidationError[] => {
const validationErrors: ValidationError[] = [];
// Color validation (first in form order)
if (savingsColor.trim().length < 1) {
validationErrors.push({
field: 'savingsColor',
message: 'Please select a color for your savings',
});
}
// Name validation
if (name.trim().length < 1) {
validationErrors.push({
field: 'name',
message: 'Please enter a name',
});
}
// Amount validation
if (Number(amount) <= 0 || isNaN(Number(amount))) {
validationErrors.push({
field: 'amount',
message: 'Please enter a valid amount',
});
}
return validationErrors;
};
// Flexible savings specific validation
export const validateFlexibleSavings = (
autoSave: boolean,
selectedFrequency: FrequencyType,
periodicSavingsAmount: string,
amountPercentage: string,
selectedTypeOfDeduction: DeductionNameType,
startDate: any,
endDate: any
): ValidationError[] => {
const validationErrors: ValidationError[] = [];
if (autoSave) {
// Frequency validation
if (selectedFrequency.length < 1) {
validationErrors.push({
field: 'frequency',
message: 'Please select a frequency',
});
}
// Periodic amount validation for non-SaveAsYouCollect frequencies
if (getFrequencyEnum(selectedFrequency) !== 4) {
if (
Number(periodicSavingsAmount) <= 0 ||
isNaN(Number(periodicSavingsAmount))
) {
validationErrors.push({
field: 'periodicSavingsAmount',
message: 'Please enter a valid amount',
});
}
} else {
// SaveAsYouCollect specific validation
if (!amountPercentage) {
validationErrors.push({
field: 'amountPercentage',
message: selectedTypeOfDeduction === 'Flat rate'
? 'Please enter a valid amount'
: 'Please enter a valid percentage',
});
}
}
// Date validations (only required when autoSave is enabled)
if (!startDate) {
validationErrors.push({
field: 'startDate',
message: 'Please select a start date',
});
}
if (!endDate) {
validationErrors.push({
field: 'endDate',
message: 'Please select an end date',
});
}
}
return validationErrors;
};
// Locked savings specific validation
export const validateLockedSavings = (
lockDurationDays: number,
minimumLockDurationDays: number,
editMode?: boolean,
selectedTier?: any,
maxDaysAvailable?: number
): ValidationError[] => {
const validationErrors: ValidationError[] = [];
if (!editMode) {
// First check if a tier is selected
if (!selectedTier) {
validationErrors.push({
field: 'tierSelection',
message: 'Please choose how long you want to save for',
});
return validationErrors; // Return early if no tier selected
}
// Lock duration validation
if (!lockDurationDays || lockDurationDays <= 0) {
validationErrors.push({
field: 'lockDurationDays',
message: 'Please enter a valid lock duration',
});
} else if (maxDaysAvailable && lockDurationDays > maxDaysAvailable) {
// Prevent values above maximum available range
validationErrors.push({
field: 'lockDurationDays',
message: `Lock duration cannot exceed ${maxDaysAvailable} days`,
});
} else if (lockDurationDays < selectedTier.minDays || lockDurationDays > selectedTier.maxDays) {
validationErrors.push({
field: 'lockDurationDays',
message: `Duration must be between ${selectedTier.minDays} and ${selectedTier.maxDays} days for the selected duration range`,
});
} else if (lockDurationDays < minimumLockDurationDays) {
validationErrors.push({
field: 'lockDurationDays',
message: `Lock duration must be at least ${minimumLockDurationDays} days`,
});
}
}
return validationErrors;
};