Skip to content

Commit 2e9facc

Browse files
feat: Implement mobile-optimized CRM dashboard table cells and headers with status emojis.
1 parent 315412e commit 2e9facc

File tree

10 files changed

+141
-33
lines changed

10 files changed

+141
-33
lines changed

src/shared/constants/constants.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ export const STATUSES_DICT: Record<Statuces, string> = {
2121
[Statuces.rejected]: 'Отменен',
2222
};
2323

24+
export const STATUSES_MOBILE_DICT: Record<Statuces, string> = {
25+
[Statuces.submited]: '📝',
26+
[Statuces.in_work]: '⚙️',
27+
[Statuces.accomplished]: '🟢',
28+
[Statuces.rejected]: '❌',
29+
};
30+
2431
export enum PaymentStatuces {
2532
paid = 'paid',
2633
not_paid = 'not_paid',
@@ -31,6 +38,11 @@ export const PAYMENT_STATUCES_DICT: Record<PaymentStatuces, string> = {
3138
[PaymentStatuces.not_paid]: 'Не оплачен',
3239
};
3340

41+
export const PAYMENT_STATUCES_MOBILE_DICT: Record<PaymentStatuces, string> = {
42+
[PaymentStatuces.paid]: '🟢',
43+
[PaymentStatuces.not_paid]: '🔴',
44+
};
45+
3446
export enum ALLOWED_EXTENSIONS_ENUM {
3547
STL = 'stl',
3648
THREE_MF = '3mf',

src/widgets/CRMDashboard/Table/api/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@ export const getFileName = (url: string) => {
5757
throw Error();
5858
}
5959
} catch (_) {
60-
return 'не поддерживаемый формат файла';
60+
return '---';
6161
}
6262
};

src/widgets/CRMDashboard/Table/model/index.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ export const orderTypeColumns = [
5454
label: 'оплата',
5555
visible: true,
5656
},
57-
5857
{
5958
key: 'created_at',
60-
label: 'дата создания',
59+
label: 'дата',
6160
visible: true,
6261
},
6362
];
@@ -90,8 +89,19 @@ export const consultationTypeColumns = [
9089
},
9190
{
9291
key: 'created_at',
93-
label: 'дата создания',
92+
label: 'дата',
9493
visible: true,
9594
},
9695
];
9796
export const hideNotvisible = (i: { visible: boolean }) => i.visible;
97+
98+
export const EMOJI_LABELS = {
99+
file_path: '📄',
100+
phone: '☎️',
101+
email: '✉️',
102+
order_status: '📦',
103+
payment_status: '💳',
104+
created_at: '📅',
105+
contact: '💬',
106+
name: '👤',
107+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React from 'react';
2+
import cn from 'classnames';
3+
import s from './style.module.scss';
4+
import { getFileName } from '../../api/utils';
5+
import {
6+
PAYMENT_STATUCES_DICT,
7+
PAYMENT_STATUCES_MOBILE_DICT,
8+
STATUSES_DICT,
9+
STATUSES_MOBILE_DICT,
10+
} from '@/shared/constants/constants';
11+
import { useWindowWidth } from '@/shared/hooks';
12+
13+
type CellProps = {
14+
path: string;
15+
value: string;
16+
};
17+
18+
export const Cell: React.FC<CellProps> = ({ path, value }) => {
19+
const width = useWindowWidth();
20+
21+
if (path === 'file_path') {
22+
return <div className={s.container}>{getFileName(value)}</div>;
23+
}
24+
25+
if (path === 'order_status') {
26+
const isMobile = width < 600;
27+
const DICT = isMobile ? STATUSES_MOBILE_DICT : STATUSES_DICT;
28+
return (
29+
<div className={cn(s.container, s.centered)}>
30+
{DICT[value as keyof typeof DICT]}
31+
</div>
32+
);
33+
}
34+
35+
if (path === 'payment_status') {
36+
const isMobile = width < 600;
37+
const DICT = isMobile
38+
? PAYMENT_STATUCES_MOBILE_DICT
39+
: PAYMENT_STATUCES_DICT;
40+
return (
41+
<div className={cn(s.container, s.centered)}>
42+
{DICT[value as keyof typeof DICT]}
43+
</div>
44+
);
45+
}
46+
47+
if (path === 'created_at') {
48+
const dateString = new Date(value).toLocaleDateString('ru-RU', {
49+
day: '2-digit',
50+
month: '2-digit',
51+
year: '2-digit',
52+
});
53+
return <div className={cn(s.container, s.centered)}>{dateString}</div>;
54+
}
55+
const l = (value || '').trim() || '---';
56+
return <div className={s.container}>{l}</div>;
57+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.container {
2+
flex: 1;
3+
overflow: hidden;
4+
white-space: nowrap;
5+
text-overflow: ellipsis;
6+
font-size: 13px;
7+
box-sizing: border-box;
8+
padding-right: 5px;
9+
padding-left: 5px;
10+
}
11+
12+
.centered {
13+
display: flex;
14+
flex-direction: column;
15+
align-items: center;
16+
justify-content: center;
17+
}

src/widgets/CRMDashboard/Table/ui/TableBody/index.tsx

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { CircularProgress } from '@mui/material';
1212
import { crmPreviewModalState } from '@/shared/state/crmPreviewModal/state';
1313
import { PrintOrderEntity } from '@/entities/order';
1414
import { ConsultationEntity } from '@/entities/consultation';
15-
import { getFileName } from '../../api/utils';
15+
import { Cell } from '../Cell';
1616
import s from './style.module.scss';
1717

1818
export const TableBody = observer(() => {
@@ -37,20 +37,13 @@ export const TableBody = observer(() => {
3737
key={i.id}
3838
className={s.containerRow}
3939
>
40-
{orderTypeColumns.filter(hideNotvisible).map((value) => {
41-
if (value.key === 'file_path') {
42-
return (
43-
<div key={value.key} className={s.cell}>
44-
{getFileName(get(i, value.key, '') || '')}
45-
</div>
46-
);
47-
}
48-
return (
49-
<div key={value.key} className={s.cell}>
50-
{get(i, value.key, '-')}
51-
</div>
52-
);
53-
})}
40+
{orderTypeColumns.filter(hideNotvisible).map((value) => (
41+
<Cell
42+
key={value.key}
43+
path={value.key}
44+
value={get(i, value.key, '---')}
45+
/>
46+
))}
5447
</button>
5548
))}
5649
{pending ? (
@@ -73,9 +66,11 @@ export const TableBody = observer(() => {
7366
className={s.containerRow}
7467
>
7568
{consultationTypeColumns.filter(hideNotvisible).map((value) => (
76-
<div key={value.key} className={s.cell}>
77-
{get(i, value.key, '-')}
78-
</div>
69+
<Cell
70+
key={value.key}
71+
path={value.key}
72+
value={get(i, value.key, '-')}
73+
/>
7974
))}
8075
</button>
8176
))}

src/widgets/CRMDashboard/Table/ui/TableBody/style.module.scss

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,3 @@
2828
left: calc(50% - 20px);
2929
}
3030
}
31-
32-
.cell {
33-
flex: 1;
34-
overflow: hidden;
35-
white-space: nowrap;
36-
text-overflow: ellipsis;
37-
font-size: 13px;
38-
}

src/widgets/CRMDashboard/Table/ui/TableHeader/index.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ import {
99
hideNotvisible,
1010
} from '../../model';
1111
import cn from 'classnames';
12+
import { ColumnLabel } from './ui/ColumnLabel';
13+
import { useWindowWidth } from '@/shared/hooks';
1214

1315
export const TableHeader = observer(() => {
1416
const { orderType } = crmFilterState;
15-
17+
const width = useWindowWidth();
18+
const isMobile = width <= 450;
1619
if (orderType === 'print_order') {
1720
return (
1821
<div className={s.container}>
@@ -23,7 +26,7 @@ export const TableHeader = observer(() => {
2326
[s.columnWithBorder]: index < a.length - 1,
2427
})}
2528
>
26-
{i.label}
29+
<ColumnLabel isMobile={isMobile} type={i.key} label={i.label} />
2730
</div>
2831
))}
2932
</div>
@@ -39,7 +42,7 @@ export const TableHeader = observer(() => {
3942
[s.columnWithBorder]: index < a.length - 1,
4043
})}
4144
>
42-
{i.label}
45+
<ColumnLabel isMobile={isMobile} type={i.key} label={i.label} />
4346
</div>
4447
))}
4548
</div>

src/widgets/CRMDashboard/Table/ui/TableHeader/style.module.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
justify-content: center;
1818
align-items: center;
1919
font-size: 13px;
20+
overflow: hidden;
21+
white-space: nowrap;
22+
2023
&WithBorder {
2124
&::after {
2225
position: absolute;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { EMOJI_LABELS } from '@/widgets/CRMDashboard/Table/model';
2+
import { get } from 'lodash';
3+
import React from 'react';
4+
5+
type ColumnLabelProps = {
6+
type: string;
7+
label: string;
8+
isMobile: boolean;
9+
};
10+
export const ColumnLabel: React.FC<ColumnLabelProps> = ({
11+
type,
12+
label,
13+
isMobile,
14+
}) => {
15+
if (isMobile) {
16+
return <>{get(EMOJI_LABELS, type, label)}</>;
17+
}
18+
return <>{label}</>;
19+
};

0 commit comments

Comments
 (0)