feat(migrations): add README for node-pg-migrate and enhance frontend configuration

- Created a README file for database migrations using node-pg-migrate, detailing commands, file format, best practices, and an example migration.
- Added a Vite configuration file for the frontend, including plugin setup, alias resolution, build optimizations, and responsive design adjustments for task list components.
- Updated i18n configuration to preload the 'home' namespace for improved localization.
- Enhanced task list styling with responsive design features for better mobile usability.
This commit is contained in:
chamiakJ
2025-07-23 07:46:39 +05:30
parent e3c002b088
commit a6286eb2b8
5 changed files with 169 additions and 10 deletions

View File

@@ -10,6 +10,7 @@ i18n
.init({
fallbackLng: 'en',
defaultNS: 'common',
ns: ['common', 'home'], // Preload home namespace
interpolation: {
escapeValue: false,

View File

@@ -6,3 +6,81 @@
.ant-table-row:hover .row-action-button {
opacity: 1;
}
/* Responsive styles for task list */
@media (max-width: 768px) {
.task-list-card .ant-card-head {
flex-direction: column;
gap: 12px;
}
.task-list-card .ant-card-head-title {
flex: 1;
width: 100%;
}
.task-list-card .ant-card-extra {
width: 100%;
justify-content: space-between;
}
.task-list-mobile-header {
flex-direction: column;
gap: 8px;
align-items: stretch !important;
}
.task-list-mobile-controls {
flex-direction: column;
gap: 8px;
align-items: stretch !important;
}
.task-list-mobile-select {
width: 100% !important;
}
.task-list-mobile-segmented {
width: 100% !important;
}
}
@media (max-width: 576px) {
.task-list-card .ant-table {
font-size: 12px;
}
.task-list-card .ant-table-thead > tr > th {
padding: 8px 4px;
font-size: 12px;
}
.task-list-card .ant-table-tbody > tr > td {
padding: 8px 4px;
}
.row-action-button {
opacity: 1; /* Always show on mobile */
}
/* Hide project column on very small screens */
.task-list-card .ant-table-thead > tr > th:nth-child(2),
.task-list-card .ant-table-tbody > tr > td:nth-child(2) {
display: none;
}
}
/* Table responsive container */
.task-list-card .ant-table-container {
overflow-x: auto;
}
@media (max-width: 768px) {
.task-list-card .ant-table-wrapper {
overflow-x: auto;
}
.task-list-card .ant-table {
min-width: 600px;
}
}

View File

@@ -15,6 +15,7 @@ import {
} from 'antd';
import React, { useState, useMemo, useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useMediaQuery } from 'react-responsive';
import ListView from './list-view';
import CalendarView from './calendar-view';
@@ -61,21 +62,22 @@ const TasksList: React.FC = React.memo(() => {
refetchOnFocus: false,
});
const { t } = useTranslation('home');
const { t, ready } = useTranslation('home');
const { model } = useAppSelector(state => state.homePageReducer);
const isMobile = useMediaQuery({ maxWidth: 768 });
const taskModes = useMemo(
() => [
{
value: 0,
label: t('home:tasks.assignedToMe'),
label: ready ? t('tasks.assignedToMe') : 'Assigned to me',
},
{
value: 1,
label: t('home:tasks.assignedByMe'),
label: ready ? t('tasks.assignedByMe') : 'Assigned by me',
},
],
[t]
[t, ready]
);
const handleSegmentChange = (value: 'List' | 'Calendar') => {
@@ -123,7 +125,7 @@ const TasksList: React.FC = React.memo(() => {
<span>{t('tasks.name')}</span>
</Flex>
),
width: '40%',
width: isMobile ? '50%' : '40%',
render: (_, record) => (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Tooltip title={record.name}>
@@ -155,7 +157,7 @@ const TasksList: React.FC = React.memo(() => {
{
key: 'project',
title: t('tasks.project'),
width: '25%',
width: isMobile ? '30%' : '25%',
render: (_, record) => {
return (
<Tooltip title={record.project_name}>
@@ -185,7 +187,7 @@ const TasksList: React.FC = React.memo(() => {
render: (_, record) => <HomeTasksDatePicker record={record} />,
},
],
[t, data?.body?.total, currentPage, pageSize, handlePageChange]
[t, data?.body?.total, currentPage, pageSize, handlePageChange, isMobile]
);
const handleTaskModeChange = (value: number) => {
@@ -210,23 +212,27 @@ const TasksList: React.FC = React.memo(() => {
);
}, [dispatch]);
return (
<Card
className="task-list-card"
title={
<Flex gap={8} align="center">
<Flex gap={8} align="center" className="task-list-mobile-header">
<Typography.Title level={5} style={{ margin: 0 }}>
{t('tasks.tasks')}
</Typography.Title>
<Select
defaultValue={taskModes[0].label}
value={homeTasksConfig.tasks_group_by || 0}
options={taskModes}
onChange={value => handleTaskModeChange(+value)}
fieldNames={{ label: 'label', value: 'value' }}
className="task-list-mobile-select"
style={{ minWidth: 160 }}
/>
</Flex>
}
extra={
<Flex gap={8} align="center">
<Flex gap={8} align="center" className="task-list-mobile-controls">
<Tooltip title={t('tasks.refresh')} trigger={'hover'}>
<Button
shape="circle"
@@ -241,6 +247,7 @@ const TasksList: React.FC = React.memo(() => {
]}
defaultValue="List"
onChange={handleSegmentChange}
className="task-list-mobile-segmented"
/>
</Flex>
}
@@ -283,6 +290,7 @@ const TasksList: React.FC = React.memo(() => {
rowClassName={() => 'custom-row-height'}
loading={homeTasksFetching && skipAutoRefetch}
pagination={false}
scroll={{ x: 'max-content' }}
/>
<div