- Added TaskDialog component with functionality to create and edit tasks. - Integrated form validation and error handling for task inputs. - Implemented step management within tasks, including adding and deleting steps. - Styled TaskDialog with CSS for improved user experience. feat: Create SmartPackagesRoutes for navigation and routing - Established routing for smart packages, including create and edit functionalities. - Added loading state management for better user feedback during data fetching. - Integrated SmartPackagesMenu for navigation within the smart packages section. feat: Add utility functions for formatting data - Implemented formatting utilities for currency, time, date, and percentages. - Ensured consistent formatting across the application for better readability. chore: Update database schema for smart packages - Extended material_packages table with new fields for estimated hours, hourly rate, and difficulty level. - Created smart_package_tasks and smart_package_steps tables for task management. - Added foreign key relationships and indexes for improved database performance. test: Add API tests for smart packages functionality - Created test suite for validating smart packages API endpoints. - Included tests for CRUD operations on smart packages and retrieval of categories and types.
107 lines
2.0 KiB
JavaScript
107 lines
2.0 KiB
JavaScript
/**
|
|
* Formattering utilities
|
|
* Hjælpefunktioner til formattering af tal, valuta, tid og dato
|
|
*/
|
|
|
|
/**
|
|
* Formatér tal som dansk valuta (DKK)
|
|
*/
|
|
export const formatCurrency = (amount, decimals = 2) => {
|
|
if (amount === null || amount === undefined || isNaN(amount)) {
|
|
return '0,00 kr';
|
|
}
|
|
|
|
return new Intl.NumberFormat('da-DK', {
|
|
style: 'currency',
|
|
currency: 'DKK',
|
|
minimumFractionDigits: decimals,
|
|
maximumFractionDigits: decimals
|
|
}).format(amount);
|
|
};
|
|
|
|
/**
|
|
* Formatér tid i timer
|
|
*/
|
|
export const formatTime = (hours) => {
|
|
if (hours === null || hours === undefined || isNaN(hours)) {
|
|
return '0 timer';
|
|
}
|
|
|
|
const h = parseFloat(hours);
|
|
|
|
if (h === 1) {
|
|
return '1 time';
|
|
}
|
|
|
|
return `${h.toFixed(1)} timer`;
|
|
};
|
|
|
|
/**
|
|
* Formatér dato til dansk format
|
|
*/
|
|
export const formatDate = (dateString) => {
|
|
if (!dateString) {
|
|
return '-';
|
|
}
|
|
|
|
const date = new Date(dateString);
|
|
|
|
if (isNaN(date.getTime())) {
|
|
return '-';
|
|
}
|
|
|
|
return new Intl.DateTimeFormat('da-DK', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
}).format(date);
|
|
};
|
|
|
|
/**
|
|
* Formatér dato og tid til dansk format
|
|
*/
|
|
export const formatDateTime = (dateString) => {
|
|
if (!dateString) {
|
|
return '-';
|
|
}
|
|
|
|
const date = new Date(dateString);
|
|
|
|
if (isNaN(date.getTime())) {
|
|
return '-';
|
|
}
|
|
|
|
return new Intl.DateTimeFormat('da-DK', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
}).format(date);
|
|
};
|
|
|
|
/**
|
|
* Formatér tal med tusinde-separatorer
|
|
*/
|
|
export const formatNumber = (number, decimals = 0) => {
|
|
if (number === null || number === undefined || isNaN(number)) {
|
|
return '0';
|
|
}
|
|
|
|
return new Intl.NumberFormat('da-DK', {
|
|
minimumFractionDigits: decimals,
|
|
maximumFractionDigits: decimals
|
|
}).format(number);
|
|
};
|
|
|
|
/**
|
|
* Formatér procent
|
|
*/
|
|
export const formatPercent = (value, decimals = 1) => {
|
|
if (value === null || value === undefined || isNaN(value)) {
|
|
return '0%';
|
|
}
|
|
|
|
return `${parseFloat(value).toFixed(decimals)}%`;
|
|
};
|