mautourco-components 0.2.44 → 0.2.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,6 +11,6 @@ var Input = function (_a) {
11
11
  disabled: 'input-field--disabled',
12
12
  };
13
13
  var inputClasses = "".concat(baseClasses, " ").concat(variantClasses[variant], " ").concat(icon ? "input-field--with-icon input-field--icon-".concat(iconPosition) : '', " ").concat(className).trim();
14
- return (_jsxs("div", { className: "input-wrapper ".concat(icon ? 'input-wrapper--with-icon' : '').trim(), children: [icon && iconPosition === 'leading' && (_jsx("span", { className: "input-icon input-icon--leading", children: _jsx(Icon, { name: icon, size: "sm" }) })), _jsx("input", { id: id, type: type, className: inputClasses, placeholder: placeholder, value: value, disabled: disabled || variant === 'disabled', onChange: onChange, onFocus: onFocus, onBlur: onBlur }), icon && iconPosition === 'trailing' && (_jsx("span", { className: "input-icon input-icon--trailing", children: _jsx(Icon, { name: icon, size: "sm" }) }))] }));
14
+ return (_jsxs("div", { className: "input-wrapper ".concat(icon ? 'input-wrapper--with-icon' : '').trim(), children: [icon && iconPosition === 'leading' && (_jsx("span", { className: "input-icon input-icon--leading", children: _jsx(Icon, { name: icon, size: "sm" }) })), _jsx("input", { id: id, type: type, className: inputClasses, placeholder: placeholder, value: value, disabled: disabled || variant === 'disabled', onInput: onChange, onFocus: onFocus, onBlur: onBlur }), icon && iconPosition === 'trailing' && (_jsx("span", { className: "input-icon input-icon--trailing", children: _jsx(Icon, { name: icon, size: "sm" }) }))] }));
15
15
  };
16
16
  export default Input;
@@ -8,6 +8,6 @@ export interface QuoteHeaderProps {
8
8
  /** Callback to create a new quote */
9
9
  onNewQuote: () => void;
10
10
  onFilterChange?: (filter: FilterType, value: string) => void;
11
- currentFilter: Record<FilterType, string>;
11
+ currentFilter?: Record<FilterType, string>;
12
12
  }
13
13
  export declare function QuoteHeader(props: QuoteHeaderProps): import("react/jsx-runtime").JSX.Element;
@@ -21,7 +21,8 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  return t;
22
22
  };
23
23
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
- import { useEffect, useState } from 'react';
24
+ import debounce from 'lodash/debounce';
25
+ import { useCallback, useEffect, useRef, useState } from 'react';
25
26
  import Button from '../../atoms/Button/Button';
26
27
  import DropdownInput from '../../atoms/Inputs/DropdownInput/DropdownInput';
27
28
  import Input from '../../atoms/Inputs/Input/Input';
@@ -45,10 +46,43 @@ var filterConfig = {
45
46
  export function QuoteHeader(props) {
46
47
  var _a;
47
48
  var _b = props.current, current = _b === void 0 ? 'quotation' : _b, currentFilter = props.currentFilter, onNavigate = props.onNavigate, onNewQuote = props.onNewQuote, onFilterChange = props.onFilterChange;
48
- var _c = useState(currentFilter !== null && currentFilter !== void 0 ? currentFilter : {}), currentValue = _c[0], setCurrentValue = _c[1];
49
+ var _c = useState(currentFilter || {
50
+ date: '',
51
+ clientType: '',
52
+ fileStatus: '',
53
+ search: '',
54
+ }), currentValue = _c[0], setCurrentValue = _c[1];
49
55
  var _d = useState((_a = currentFilter === null || currentFilter === void 0 ? void 0 : currentFilter.search) !== null && _a !== void 0 ? _a : ''), searchValue = _d[0], setSearchValue = _d[1];
56
+ // Create a ref to store the debounced function
57
+ var debouncedFilterChangeRef = useRef(debounce(function (value) {
58
+ onFilterChange === null || onFilterChange === void 0 ? void 0 : onFilterChange('search', value);
59
+ setCurrentValue(function (prev) { return (__assign(__assign({}, prev), { search: value })); });
60
+ }, 500));
61
+ // Update the debounced function when onFilterChange changes
50
62
  useEffect(function () {
51
- if (Object.keys(currentFilter !== null && currentFilter !== void 0 ? currentFilter : {}).length > 0) {
63
+ // Cancel the previous debounced function
64
+ debouncedFilterChangeRef.current.cancel();
65
+ // Create a new debounced function
66
+ debouncedFilterChangeRef.current = debounce(function (value) {
67
+ onFilterChange === null || onFilterChange === void 0 ? void 0 : onFilterChange('search', value);
68
+ setCurrentValue(function (prev) { return (__assign(__assign({}, prev), { search: value })); });
69
+ }, 500);
70
+ }, [onFilterChange]);
71
+ // Cleanup debounced function on unmount
72
+ useEffect(function () {
73
+ return function () {
74
+ debouncedFilterChangeRef.current.cancel();
75
+ };
76
+ }, []);
77
+ var handleInputChange = useCallback(function (e) {
78
+ var value = e.target.value;
79
+ // Update input value immediately for responsive UI
80
+ setSearchValue(value);
81
+ // Debounce the filter change callback
82
+ debouncedFilterChangeRef.current(value);
83
+ }, []);
84
+ useEffect(function () {
85
+ if (currentFilter && Object.keys(currentFilter).length > 0) {
52
86
  var search = currentFilter.search, rest = __rest(currentFilter, ["search"]);
53
87
  setCurrentValue(rest);
54
88
  setSearchValue(search);
@@ -58,11 +92,7 @@ export function QuoteHeader(props) {
58
92
  setSearchValue('');
59
93
  }
60
94
  }, [currentFilter]);
61
- return (_jsxs("div", { className: "quote-header", children: [_jsx(Heading, { level: 4, as: "h1", className: "quote-header__title", color: "accent", children: "Quotation & Booking" }), _jsxs("div", { className: "flex gap-4", children: [_jsx(Button, { variant: current === 'quotation' ? 'primary' : 'outline-primary', className: "quote-header__button", onClick: function () { return onNavigate('quotation'); }, children: "Quotation" }), _jsx(Button, { variant: current === 'booking' ? 'primary' : 'outline-primary', className: "quote-header__button", onClick: function () { return onNavigate('booking'); }, children: "Booking" })] }), _jsxs("div", { className: "quote-header__search-container", children: [_jsx(Input, { placeholder: "Search", icon: "search", iconPosition: "leading", className: "quote-header__search", value: searchValue, onChange: function (e) {
62
- onFilterChange === null || onFilterChange === void 0 ? void 0 : onFilterChange('search', e.target.value);
63
- setCurrentValue(__assign(__assign({}, currentValue), { search: e.target.value }));
64
- setSearchValue(e.target.value);
65
- } }), _jsx(Button, { variant: "primary", leadingIcon: "plus-circle", iconSize: "md", size: "sm", onClick: onNewQuote, children: "New quote" })] }), _jsx("div", { className: "quote-header__filters", children: Object.entries(filterConfig).map(function (_a) {
95
+ return (_jsxs("div", { className: "quote-header", children: [_jsx(Heading, { level: 4, as: "h1", className: "quote-header__title", color: "accent", children: "Quotation & Booking" }), _jsxs("div", { className: "flex gap-4", children: [_jsx(Button, { variant: current === 'quotation' ? 'primary' : 'outline-primary', className: "quote-header__button", onClick: function () { return onNavigate('quotation'); }, children: "Quotation" }), _jsx(Button, { variant: current === 'booking' ? 'primary' : 'outline-primary', className: "quote-header__button", onClick: function () { return onNavigate('booking'); }, children: "Booking" })] }), _jsxs("div", { className: "quote-header__search-container", children: [_jsx(Input, { placeholder: "Search", icon: "search", iconPosition: "leading", className: "quote-header__search", value: searchValue, onChange: handleInputChange }), _jsx(Button, { variant: "primary", leadingIcon: "plus-circle", iconSize: "md", size: "sm", onClick: onNewQuote, children: "New quote" })] }), _jsx("div", { className: "quote-header__filters", children: Object.entries(filterConfig).map(function (_a) {
66
96
  var key = _a[0], value = _a[1];
67
97
  return (_jsx(DropdownInput, { placeholder: value.placeholder, options: value.options, value: currentValue[key], onSelect: function (value) {
68
98
  var _a;
@@ -11,6 +11,11 @@
11
11
  }
12
12
  }
13
13
 
14
+ .text--highlight {
15
+ background-color: var(--color-amber-100);
16
+ font-weight: 700;
17
+ }
18
+
14
19
  .table {
15
20
  width: 100%;
16
21
  border-collapse: collapse;
@@ -2,6 +2,6 @@ import { ActionDropdownType } from '@/src/types/table';
2
2
  import { BookingListItem } from '@/src/types/table/booking.types';
3
3
  import { ColumnType } from '../TableCell';
4
4
  export declare const bookingColumns: (params: {
5
- onExpand: (value?: BookingListItem) => void;
6
- onAction: (action: ActionDropdownType) => void;
5
+ onAction?: (action: ActionDropdownType) => void;
6
+ keywords?: string;
7
7
  }) => ColumnType<BookingListItem>[];
@@ -6,19 +6,32 @@ import { DateDisplay } from '../../../molecules/DateDisplay/DateDisplay';
6
6
  import { PaxChips } from '../../../molecules/PaxChips/PaxChips';
7
7
  import { actionDropdownData } from '../constant';
8
8
  export var bookingColumns = function (_a) {
9
- var onExpand = _a.onExpand, onAction = _a.onAction;
9
+ var onAction = _a.onAction, _b = _a.keywords, keywords = _b === void 0 ? '' : _b;
10
10
  return [
11
11
  {
12
12
  header: 'Quote nb.',
13
13
  key: 'booking_id',
14
14
  width: 150,
15
- cell: function (value) { return (_jsx(Text, { variant: "medium", size: "sm", children: value })); },
15
+ cell: function (value) {
16
+ if (value === void 0) { value = ''; }
17
+ var currentValue = String(value);
18
+ var regex = new RegExp("(".concat(keywords !== null && keywords !== void 0 ? keywords : '', ")"), 'gi');
19
+ if (regex.test(currentValue)) {
20
+ return (_jsx(Text, { variant: "medium", size: "sm", children: _jsx("span", { dangerouslySetInnerHTML: {
21
+ __html: currentValue.replace(regex, "<span class=\"text--highlight\">$1</span>"),
22
+ } }) }));
23
+ }
24
+ return (_jsx(Text, { variant: "medium", size: "sm", children: currentValue }));
25
+ },
16
26
  },
17
27
  {
18
28
  header: 'Client name',
19
29
  key: 'agency_name',
20
30
  width: 150,
21
- cell: function (value) { return (_jsx(Text, { variant: "medium", size: "sm", children: value })); },
31
+ cell: function (value) {
32
+ if (value === void 0) { value = ''; }
33
+ return (_jsx(Text, { variant: "medium", size: "sm", children: value }));
34
+ },
22
35
  },
23
36
  {
24
37
  header: 'Type',
@@ -61,7 +74,7 @@ export var bookingColumns = function (_a) {
61
74
  key: 'actions',
62
75
  width: 232,
63
76
  cell: function (_value, raw) {
64
- return (_jsx("div", { children: _jsxs("div", { className: "flex items-center gap-x-8", children: [_jsxs("div", { className: "flex items-center gap-x-3", children: [_jsx(Button, { variant: "secondary", size: "sm", className: "w-[89px]", children: "Proforma" }), _jsx(Button, { variant: "outline-secondary", size: "sm", className: "w-[89px]", children: "Voucher" })] }), _jsx(ActionDropdown, { data: actionDropdownData(onAction) })] }) }));
77
+ return (_jsx("div", { children: _jsxs("div", { className: "flex items-center gap-x-8", children: [_jsxs("div", { className: "flex items-center gap-x-3", children: [_jsx(Button, { variant: "secondary", size: "sm", className: "w-[89px]", children: "Proforma" }), _jsx(Button, { variant: "outline-secondary", size: "sm", className: "w-[89px]", children: "Voucher" })] }), _jsx(ActionDropdown, { data: actionDropdownData(onAction !== null && onAction !== void 0 ? onAction : (function () { })) })] }) }));
65
78
  },
66
79
  },
67
80
  ];
@@ -1,17 +1,18 @@
1
1
  declare const columns: {
2
2
  quotation: (params: {
3
- onExpand: (value?: import("../../../..").QuotationListItem) => void;
4
- onAction: (data: {
3
+ onExpand?: (value?: import("../../../..").QuotationListItem) => void;
4
+ onAction?: (data: {
5
5
  isChild?: boolean;
6
6
  quote: import("../../../..").QuotationListItem;
7
7
  }) => (action: import("../../../..").ActionDropdownType) => void;
8
+ keywords?: string;
8
9
  }) => import("../TableCell").ColumnType<import("../../../..").QuotationListItem>[];
9
10
  detailResume: (params?: {
10
11
  onRemove?: (value: import("../../../..").DetailResumeItem, index?: number) => void;
11
12
  }) => import("../TableCell").ColumnType<import("../../../..").DetailResumeItem>[];
12
13
  booking: (params: {
13
- onExpand: (value?: import("../../../../types/table/booking.types").BookingListItem) => void;
14
- onAction: (action: import("../../../..").ActionDropdownType) => void;
14
+ onAction?: (action: import("../../../..").ActionDropdownType) => void;
15
+ keywords?: string;
15
16
  }) => import("../TableCell").ColumnType<import("../../../../types/table/booking.types").BookingListItem>[];
16
17
  bookingCancelService: (params?: {
17
18
  onRemove?: (value: import("../../../..").DetailResumeItem, index?: number, childIndex?: number) => void;
@@ -2,9 +2,10 @@ import { ActionDropdownType } from '@/src/types/table/action-dropdown-type.types
2
2
  import { QuotationListItem } from '@/src/types/table/quotation.types';
3
3
  import { ColumnType } from '../TableCell';
4
4
  export declare const quotationColumns: (params: {
5
- onExpand: (value?: QuotationListItem) => void;
6
- onAction: (data: {
5
+ onExpand?: (value?: QuotationListItem) => void;
6
+ onAction?: (data: {
7
7
  isChild?: boolean;
8
8
  quote: QuotationListItem;
9
9
  }) => (action: ActionDropdownType) => void;
10
+ keywords?: string;
10
11
  }) => ColumnType<QuotationListItem>[];
@@ -7,20 +7,33 @@ import { DateDisplay } from '../../../molecules/DateDisplay/DateDisplay';
7
7
  import { cn } from '../../../../lib/utils';
8
8
  import { actionDropdownData, chipVariant, clientTypeMap } from '../constant';
9
9
  export var quotationColumns = function (_a) {
10
- var onExpand = _a.onExpand, onAction = _a.onAction;
10
+ var onExpand = _a.onExpand, onAction = _a.onAction, _b = _a.keywords, keywords = _b === void 0 ? '' : _b;
11
11
  return [
12
12
  {
13
13
  header: 'Quote nb.',
14
14
  key: 'file_nb',
15
15
  width: 150,
16
- cell: function (value) { return (_jsx(Text, { variant: "medium", size: "sm", children: value })); },
16
+ cell: function (value) {
17
+ if (value === void 0) { value = ''; }
18
+ var currentValue = String(value);
19
+ var regex = new RegExp("(".concat(keywords !== null && keywords !== void 0 ? keywords : '', ")"), 'gi');
20
+ if (regex.test(currentValue)) {
21
+ return (_jsx(Text, { variant: "medium", size: "sm", children: _jsx("span", { dangerouslySetInnerHTML: {
22
+ __html: currentValue.replace(regex, "<span class=\"text--highlight\">$1</span>"),
23
+ } }) }));
24
+ }
25
+ return (_jsx(Text, { variant: "medium", size: "sm", children: currentValue }));
26
+ },
17
27
  },
18
28
  {
19
29
  header: 'Client name',
20
30
  key: 'agency_name',
21
31
  width: 150,
22
32
  cell: function (value, _raw, _index, childIndex) {
23
- return childIndex === undefined && (_jsx(Text, { variant: "medium", size: "sm", children: value }));
33
+ if (value === void 0) { value = ''; }
34
+ if (childIndex === undefined) {
35
+ return (_jsx(Text, { variant: "medium", size: "sm", children: value }));
36
+ }
24
37
  },
25
38
  },
26
39
  {
@@ -70,12 +83,12 @@ export var quotationColumns = function (_a) {
70
83
  key: 'actions',
71
84
  width: 232,
72
85
  cell: function (_value, raw, _index, childIndex) {
73
- var _a;
86
+ var _a, _b;
74
87
  var hasChildren = raw.children && raw.children.length > 0;
75
88
  var isExpanded = (_a = raw.children) === null || _a === void 0 ? void 0 : _a.some(function (child) { return child.visible; });
76
89
  var buttonLabel = isExpanded ? 'See less' : 'See more';
77
90
  var isOnRequest = raw.status.toLowerCase() === 'on request';
78
- return (_jsx("div", { children: hasChildren ? (_jsx(Button, { variant: "outline-primary", size: "sm", trailingIcon: "chevron-down", className: cn('table__button', isExpanded && 'table__button-expanded'), onClick: function () { return onExpand(raw); }, children: buttonLabel })) : (_jsxs("div", { className: "flex items-center gap-x-8", children: [_jsx(Button, { variant: isOnRequest ? 'outline-secondary' : 'secondary', size: "sm", className: "table__button", children: isOnRequest ? 'Request to book' : 'Book now' }), _jsx(ActionDropdown, { data: actionDropdownData(onAction({ isChild: childIndex !== undefined, quote: raw })) })] })) }));
91
+ return (_jsx("div", { children: hasChildren ? (_jsx(Button, { variant: "outline-primary", size: "sm", trailingIcon: "chevron-down", className: cn('table__button', isExpanded && 'table__button-expanded'), onClick: function () { return onExpand === null || onExpand === void 0 ? void 0 : onExpand(raw); }, children: buttonLabel })) : (_jsxs("div", { className: "flex items-center gap-x-8", children: [_jsx(Button, { variant: isOnRequest ? 'outline-secondary' : 'secondary', size: "sm", className: "table__button", children: isOnRequest ? 'Request to book' : 'Book now' }), _jsx(ActionDropdown, { data: actionDropdownData((_b = onAction === null || onAction === void 0 ? void 0 : onAction({ isChild: childIndex !== undefined, quote: raw })) !== null && _b !== void 0 ? _b : (function () { })) })] })) }));
79
92
  },
80
93
  },
81
94
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mautourco-components",
3
- "version": "0.2.44",
3
+ "version": "0.2.46",
4
4
  "private": false,
5
5
  "description": "Bibliothèque de composants Motorco pour le redesign",
6
6
  "main": "dist/index.js",
@@ -56,7 +56,7 @@ const Input: React.FC<InputProps> = ({
56
56
  placeholder={placeholder}
57
57
  value={value}
58
58
  disabled={disabled || variant === 'disabled'}
59
- onChange={onChange}
59
+ onInput={onChange}
60
60
  onFocus={onFocus}
61
61
  onBlur={onBlur}
62
62
  />
@@ -1,4 +1,5 @@
1
- import { useEffect, useState } from 'react';
1
+ import debounce from 'lodash/debounce';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
3
  import Button from '../../atoms/Button/Button';
3
4
  import DropdownInput from '../../atoms/Inputs/DropdownInput/DropdownInput';
4
5
  import Input from '../../atoms/Inputs/Input/Input';
@@ -24,7 +25,7 @@ export interface QuoteHeaderProps {
24
25
 
25
26
  onFilterChange?: (filter: FilterType, value: string) => void;
26
27
 
27
- currentFilter: Record<FilterType, string>;
28
+ currentFilter?: Record<FilterType, string>;
28
29
  }
29
30
 
30
31
  const filterConfig = {
@@ -51,12 +52,51 @@ export function QuoteHeader(props: QuoteHeaderProps) {
51
52
  onFilterChange,
52
53
  } = props;
53
54
  const [currentValue, setCurrentValue] = useState<Record<FilterType, string>>(
54
- currentFilter ?? {}
55
+ currentFilter || {
56
+ date: '',
57
+ clientType: '',
58
+ fileStatus: '',
59
+ search: '',
60
+ }
55
61
  );
56
62
  const [searchValue, setSearchValue] = useState<string>(currentFilter?.search ?? '');
57
63
 
64
+ // Create a ref to store the debounced function
65
+ const debouncedFilterChangeRef = useRef(
66
+ debounce((value: string) => {
67
+ onFilterChange?.('search', value);
68
+ setCurrentValue((prev) => ({ ...prev, search: value }));
69
+ }, 500)
70
+ );
71
+
72
+ // Update the debounced function when onFilterChange changes
73
+ useEffect(() => {
74
+ // Cancel the previous debounced function
75
+ debouncedFilterChangeRef.current.cancel();
76
+ // Create a new debounced function
77
+ debouncedFilterChangeRef.current = debounce((value: string) => {
78
+ onFilterChange?.('search', value);
79
+ setCurrentValue((prev) => ({ ...prev, search: value }));
80
+ }, 500);
81
+ }, [onFilterChange]);
82
+
83
+ // Cleanup debounced function on unmount
84
+ useEffect(() => {
85
+ return () => {
86
+ debouncedFilterChangeRef.current.cancel();
87
+ };
88
+ }, []);
89
+
90
+ const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
91
+ const value = e.target.value;
92
+ // Update input value immediately for responsive UI
93
+ setSearchValue(value);
94
+ // Debounce the filter change callback
95
+ debouncedFilterChangeRef.current(value);
96
+ }, []);
97
+
58
98
  useEffect(() => {
59
- if (Object.keys(currentFilter ?? {}).length > 0) {
99
+ if (currentFilter && Object.keys(currentFilter).length > 0) {
60
100
  const { search, ...rest } = currentFilter;
61
101
  setCurrentValue(rest as Record<FilterType, string>);
62
102
  setSearchValue(search);
@@ -92,11 +132,7 @@ export function QuoteHeader(props: QuoteHeaderProps) {
92
132
  iconPosition="leading"
93
133
  className="quote-header__search"
94
134
  value={searchValue}
95
- onChange={(e) => {
96
- onFilterChange?.('search', e.target.value);
97
- setCurrentValue({ ...currentValue, search: e.target.value });
98
- setSearchValue(e.target.value);
99
- }}
135
+ onChange={handleInputChange}
100
136
  />
101
137
  <Button
102
138
  variant="primary"
@@ -7,6 +7,11 @@
7
7
  }
8
8
  }
9
9
 
10
+ .text--highlight {
11
+ background-color: var(--color-amber-100);
12
+ font-weight: 700;
13
+ }
14
+
10
15
  .table {
11
16
  width: 100%;
12
17
  border-collapse: collapse;
@@ -9,28 +9,48 @@ import { ColumnType } from '../TableCell';
9
9
  import { actionDropdownData } from '../constant';
10
10
 
11
11
  export const bookingColumns: (params: {
12
- onExpand: (value?: BookingListItem) => void;
13
- onAction: (action: ActionDropdownType) => void;
14
- }) => ColumnType<BookingListItem>[] = ({ onExpand, onAction }) => [
12
+ onAction?: (action: ActionDropdownType) => void;
13
+ keywords?: string;
14
+ }) => ColumnType<BookingListItem>[] = ({ onAction, keywords = '' }) => [
15
15
  {
16
16
  header: 'Quote nb.',
17
17
  key: 'booking_id',
18
18
  width: 150,
19
- cell: (value) => (
20
- <Text variant="medium" size="sm">
21
- {value as string}
22
- </Text>
23
- ),
19
+ cell: (value = '') => {
20
+ const currentValue = String(value as string);
21
+ const regex = new RegExp(`(${keywords ?? ''})`, 'gi');
22
+ if (regex.test(currentValue)) {
23
+ return (
24
+ <Text variant="medium" size="sm">
25
+ <span
26
+ dangerouslySetInnerHTML={{
27
+ __html: currentValue.replace(
28
+ regex,
29
+ `<span class="text--highlight">$1</span>`
30
+ ),
31
+ }}
32
+ />
33
+ </Text>
34
+ );
35
+ }
36
+ return (
37
+ <Text variant="medium" size="sm">
38
+ {currentValue}
39
+ </Text>
40
+ );
41
+ },
24
42
  },
25
43
  {
26
44
  header: 'Client name',
27
45
  key: 'agency_name',
28
46
  width: 150,
29
- cell: (value) => (
30
- <Text variant="medium" size="sm">
31
- {value as string}
32
- </Text>
33
- ),
47
+ cell: (value = '') => {
48
+ return (
49
+ <Text variant="medium" size="sm">
50
+ {value as string}
51
+ </Text>
52
+ );
53
+ },
34
54
  },
35
55
  {
36
56
  header: 'Type',
@@ -92,7 +112,7 @@ export const bookingColumns: (params: {
92
112
  Voucher
93
113
  </Button>
94
114
  </div>
95
- <ActionDropdown data={actionDropdownData(onAction)} />
115
+ <ActionDropdown data={actionDropdownData(onAction ?? (() => {}))} />
96
116
  </div>
97
117
  </div>
98
118
  );
@@ -10,32 +10,54 @@ import { ColumnType } from '../TableCell';
10
10
  import { actionDropdownData, chipVariant, clientTypeMap } from '../constant';
11
11
 
12
12
  export const quotationColumns: (params: {
13
- onExpand: (value?: QuotationListItem) => void;
14
- onAction: (data: {
13
+ onExpand?: (value?: QuotationListItem) => void;
14
+ onAction?: (data: {
15
15
  isChild?: boolean;
16
16
  quote: QuotationListItem;
17
17
  }) => (action: ActionDropdownType) => void;
18
- }) => ColumnType<QuotationListItem>[] = ({ onExpand, onAction }) => [
18
+ keywords?: string;
19
+ }) => ColumnType<QuotationListItem>[] = ({ onExpand, onAction, keywords = '' }) => [
19
20
  {
20
21
  header: 'Quote nb.',
21
22
  key: 'file_nb',
22
23
  width: 150,
23
- cell: (value) => (
24
- <Text variant="medium" size="sm">
25
- {value as string}
26
- </Text>
27
- ),
24
+ cell: (value = '') => {
25
+ const currentValue = String(value as string);
26
+ const regex = new RegExp(`(${keywords ?? ''})`, 'gi');
27
+ if (regex.test(currentValue)) {
28
+ return (
29
+ <Text variant="medium" size="sm">
30
+ <span
31
+ dangerouslySetInnerHTML={{
32
+ __html: currentValue.replace(
33
+ regex,
34
+ `<span class="text--highlight">$1</span>`
35
+ ),
36
+ }}
37
+ />
38
+ </Text>
39
+ );
40
+ }
41
+ return (
42
+ <Text variant="medium" size="sm">
43
+ {currentValue}
44
+ </Text>
45
+ );
46
+ },
28
47
  },
29
48
  {
30
49
  header: 'Client name',
31
50
  key: 'agency_name',
32
51
  width: 150,
33
- cell: (value, _raw, _index, childIndex) =>
34
- childIndex === undefined && (
35
- <Text variant="medium" size="sm">
36
- {value as string}
37
- </Text>
38
- ),
52
+ cell: (value = '', _raw, _index, childIndex) => {
53
+ if (childIndex === undefined) {
54
+ return (
55
+ <Text variant="medium" size="sm">
56
+ {value as string}
57
+ </Text>
58
+ );
59
+ }
60
+ },
39
61
  },
40
62
  {
41
63
  header: 'File status',
@@ -138,7 +160,7 @@ export const quotationColumns: (params: {
138
160
  size="sm"
139
161
  trailingIcon="chevron-down"
140
162
  className={cn('table__button', isExpanded && 'table__button-expanded')}
141
- onClick={() => onExpand(raw)}>
163
+ onClick={() => onExpand?.(raw)}>
142
164
  {buttonLabel}
143
165
  </Button>
144
166
  ) : (
@@ -151,7 +173,8 @@ export const quotationColumns: (params: {
151
173
  </Button>
152
174
  <ActionDropdown
153
175
  data={actionDropdownData(
154
- onAction({ isChild: childIndex !== undefined, quote: raw })
176
+ onAction?.({ isChild: childIndex !== undefined, quote: raw }) ??
177
+ (() => {})
155
178
  )}
156
179
  />
157
180
  </div>