mautourco-components 0.2.13 → 0.2.15
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.
- package/dist/components/atoms/Icon/icons/PlusCircleIcon.d.ts +12 -0
- package/dist/components/atoms/Icon/icons/PlusCircleIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/QuotationIcon.d.ts +8 -0
- package/dist/components/atoms/Icon/icons/QuotationIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/registry.d.ts +2 -0
- package/dist/components/atoms/Icon/icons/registry.js +4 -0
- package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.js +15 -3
- package/dist/components/organisms/MultipleQuotationDocket/MultipleQuotationDocket.d.ts +64 -0
- package/dist/components/organisms/MultipleQuotationDocket/MultipleQuotationDocket.js +45 -0
- package/dist/components/organisms/MultipleQuotationDocket/index.d.ts +2 -0
- package/dist/components/organisms/MultipleQuotationDocket/index.js +1 -0
- package/dist/components/organisms/QuoteHeader/QuoteHeader.css +2142 -0
- package/dist/components/organisms/QuoteHeader/QuoteHeader.d.ts +12 -0
- package/dist/components/organisms/QuoteHeader/QuoteHeader.js +41 -0
- package/dist/components/organisms/QuoteHeader/constant.d.ts +3 -0
- package/dist/components/organisms/QuoteHeader/constant.js +8 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/styles/components/dropdown.css +7 -6
- package/dist/styles/components/forms.css +18 -9
- package/dist/styles/components/organism/multiple-quotation-docket.css +2304 -0
- package/package.json +1 -1
- package/src/components/atoms/Icon/icons/PlusCircleIcon.tsx +60 -0
- package/src/components/atoms/Icon/icons/QuotationIcon.tsx +50 -0
- package/src/components/atoms/Icon/icons/registry.tsx +4 -0
- package/src/components/atoms/Inputs/DropdownInput/DropdownInput.tsx +29 -17
- package/src/components/organisms/CarBookingCard/index.ts +1 -0
- package/src/components/organisms/MultipleQuotationDocket/MultipleQuotationDocket.tsx +349 -0
- package/src/components/organisms/MultipleQuotationDocket/index.ts +6 -0
- package/src/components/organisms/QuoteHeader/QuoteHeader.css +37 -0
- package/src/components/organisms/QuoteHeader/QuoteHeader.tsx +93 -0
- package/src/components/organisms/QuoteHeader/constant.ts +8 -0
- package/src/styles/components/dropdown.css +7 -6
- package/src/styles/components/forms.css +18 -11
- package/src/styles/components/organism/multiple-quotation-docket.css +222 -0
package/package.json
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface PlusCircleIconProps {
|
|
4
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
5
|
+
className?: string;
|
|
6
|
+
color?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Couleur par défaut si aucune couleur n'est spécifiée
|
|
9
|
+
*/
|
|
10
|
+
defaultColor?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const PlusCircleIcon: React.FC<PlusCircleIconProps> = ({
|
|
14
|
+
size = 'md',
|
|
15
|
+
className = '',
|
|
16
|
+
color,
|
|
17
|
+
}) => {
|
|
18
|
+
const getSizeClasses = () => {
|
|
19
|
+
switch (size) {
|
|
20
|
+
case 'xs':
|
|
21
|
+
return 'w-3 h-3';
|
|
22
|
+
case 'sm':
|
|
23
|
+
return 'w-4 h-4';
|
|
24
|
+
case 'md':
|
|
25
|
+
return 'w-5 h-5';
|
|
26
|
+
case 'lg':
|
|
27
|
+
return 'w-6 h-6';
|
|
28
|
+
case 'xl':
|
|
29
|
+
return 'w-8 h-8';
|
|
30
|
+
default:
|
|
31
|
+
return 'w-5 h-5';
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const sizeClasses = getSizeClasses();
|
|
36
|
+
const colorClass = color ? `text-${color}` : 'text-current';
|
|
37
|
+
const classes = `${sizeClasses} ${colorClass} ${className}`;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<svg
|
|
41
|
+
className={classes}
|
|
42
|
+
viewBox="0 0 16 16"
|
|
43
|
+
fill="none"
|
|
44
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
45
|
+
<g clip-path="url(#clip0_7074_66340)">
|
|
46
|
+
<path
|
|
47
|
+
d="M13.915 8.00098C13.915 4.7334 11.2666 2.08416 7.99902 2.08398C4.73134 2.08398 2.08203 4.73329 2.08203 8.00098C2.08221 11.2685 4.73145 13.917 7.99902 13.917C11.2664 13.9168 13.9149 11.2684 13.915 8.00098ZM7.24902 10.667V8.75098H5.33203C4.91793 8.75098 4.58221 8.41504 4.58203 8.00098C4.58203 7.58676 4.91782 7.25098 5.33203 7.25098H7.24902V5.33398C7.24902 4.91977 7.58481 4.58398 7.99902 4.58398C8.41309 4.58416 8.74902 4.91988 8.74902 5.33398V7.25098H10.665L10.7422 7.25488C11.1203 7.29337 11.415 7.61271 11.415 8.00098C11.4149 8.38912 11.1202 8.70862 10.7422 8.74707L10.665 8.75098H8.74902V10.667C8.74902 11.0811 8.41309 11.4168 7.99902 11.417C7.58481 11.417 7.24902 11.0812 7.24902 10.667ZM15.415 8.00098C15.4149 12.0968 12.0949 15.4168 7.99902 15.417C3.90302 15.417 0.582208 12.0969 0.582031 8.00098C0.582031 3.90487 3.90291 0.583984 7.99902 0.583984C12.095 0.584161 15.415 3.90497 15.415 8.00098Z"
|
|
48
|
+
fill="white"
|
|
49
|
+
/>
|
|
50
|
+
</g>
|
|
51
|
+
<defs>
|
|
52
|
+
<clipPath id="clip0_7074_66340">
|
|
53
|
+
<rect width="16" height="16" fill="white" />
|
|
54
|
+
</clipPath>
|
|
55
|
+
</defs>
|
|
56
|
+
</svg>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default PlusCircleIcon;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface QuotationIconProps {
|
|
4
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
5
|
+
className?: string;
|
|
6
|
+
color?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const QuotationIcon: React.FC<QuotationIconProps> = ({
|
|
10
|
+
size = 'md',
|
|
11
|
+
className = '',
|
|
12
|
+
color,
|
|
13
|
+
}) => {
|
|
14
|
+
const getSizeClasses = () => {
|
|
15
|
+
switch (size) {
|
|
16
|
+
case 'xs':
|
|
17
|
+
return 'w-3 h-3';
|
|
18
|
+
case 'sm':
|
|
19
|
+
return 'w-4 h-4';
|
|
20
|
+
case 'md':
|
|
21
|
+
return 'w-5 h-5';
|
|
22
|
+
case 'lg':
|
|
23
|
+
return 'w-6 h-6';
|
|
24
|
+
case 'xl':
|
|
25
|
+
return 'w-8 h-8';
|
|
26
|
+
default:
|
|
27
|
+
return 'w-5 h-5';
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const sizeClasses = getSizeClasses();
|
|
32
|
+
const colorClass = color ? `text-${color}` : 'text-current';
|
|
33
|
+
const classes = `${sizeClasses} ${colorClass} ${className}`;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<svg
|
|
37
|
+
className={classes}
|
|
38
|
+
viewBox="0 0 22 20"
|
|
39
|
+
fill="none"
|
|
40
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
41
|
+
<path
|
|
42
|
+
d="M10 16V17C10 17.3444 9.93703 17.6814 9.82422 18H19C19.2652 18 19.5195 17.8946 19.707 17.707C19.8946 17.5195 20 17.2652 20 17V16H10ZM14 9C14.5523 9 15 9.44771 15 10C15 10.5523 14.5523 11 14 11H9C8.44771 11 8 10.5523 8 10C8 9.44771 8.44771 9 9 9H14ZM14 5C14.5523 5 15 5.44772 15 6C15 6.55228 14.5523 7 14 7H9C8.44771 7 8 6.55228 8 6C8 5.44772 8.44771 5 9 5H14ZM4 3C4 2.73478 3.89457 2.4805 3.70703 2.29297C3.54289 2.12883 3.32763 2.02757 3.09863 2.00488L3 2C2.73478 2 2.4805 2.10543 2.29297 2.29297C2.10543 2.4805 2 2.73478 2 3V5H4V3ZM6 17L6.00488 17.0986C6.02757 17.3276 6.12883 17.5429 6.29297 17.707C6.48051 17.8946 6.73478 18 7 18C7.26522 18 7.51949 17.8946 7.70703 17.707C7.89457 17.5195 8 17.2652 8 17V16C8 15.4696 8.21087 14.961 8.58594 14.5859C8.96101 14.2109 9.46957 14 10 14H17V3C17 2.73478 16.8946 2.48051 16.707 2.29297C16.5195 2.10543 16.2652 2 16 2H5.82422C5.93703 2.31859 6 2.65558 6 3V17ZM19 14H20C20.5304 14 21.039 14.2109 21.4141 14.5859C21.7891 14.961 22 15.4696 22 16V17C22 17.7957 21.6837 18.5585 21.1211 19.1211C20.5585 19.6837 19.7957 20 19 20H7C6.20435 20 5.44151 19.6837 4.87891 19.1211C4.3163 18.5585 4 17.7957 4 17V7H2C1.46957 7 0.96101 6.78913 0.585938 6.41406C0.210865 6.03899 0 5.53043 0 5V3C0 2.20435 0.316297 1.44152 0.878906 0.878906C1.3711 0.386708 2.01649 0.0829076 2.70312 0.0146484L3 0H16C16.7957 0 17.5585 0.316297 18.1211 0.878906C18.6837 1.44151 19 2.20435 19 3V14Z"
|
|
43
|
+
fill="currentColor"
|
|
44
|
+
/>
|
|
45
|
+
</svg>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default QuotationIcon;
|
|
50
|
+
|
|
@@ -35,7 +35,9 @@ import NightIcon from './NightIcon';
|
|
|
35
35
|
import PlaneIcon from './PlaneIcon';
|
|
36
36
|
import PlaneLandingOutlineIcon from './PlaneLandingOutlineIcon';
|
|
37
37
|
import PlaneTakeoffOutlineIcon from './PlaneTakeoffOutlineIcon';
|
|
38
|
+
import PlusCircleIcon from './PlusCircleIcon';
|
|
38
39
|
import PlusIcon from './PlusIcon';
|
|
40
|
+
import QuotationIcon from './QuotationIcon';
|
|
39
41
|
import Search from './Search';
|
|
40
42
|
import Settings from './Settings';
|
|
41
43
|
import ShipIcon from './ShipIcon';
|
|
@@ -108,6 +110,7 @@ export const ICONS = {
|
|
|
108
110
|
linkedin: LinkedInIcon as unknown as IconComponent,
|
|
109
111
|
plus: PlusIcon as unknown as IconComponent,
|
|
110
112
|
minus: MinusIcon as unknown as IconComponent,
|
|
113
|
+
quotation: QuotationIcon as unknown as IconComponent,
|
|
111
114
|
home: HomeIcon as unknown as IconComponent,
|
|
112
115
|
plane: PlaneIcon as unknown as IconComponent,
|
|
113
116
|
ship: ShipIcon as unknown as IconComponent,
|
|
@@ -122,6 +125,7 @@ export const ICONS = {
|
|
|
122
125
|
bus: BusIcon as unknown as IconComponent,
|
|
123
126
|
map: MapIcon as unknown as IconComponent,
|
|
124
127
|
wallet: WalletIcon as unknown as IconComponent,
|
|
128
|
+
'plus-circle': PlusCircleIcon as unknown as IconComponent,
|
|
125
129
|
} as const satisfies Record<string, IconComponent>;
|
|
126
130
|
|
|
127
131
|
export type IconName = keyof typeof ICONS;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import Icon from '../../Icon/Icon';
|
|
3
3
|
import Spinner from '../../Spinner/Spinner';
|
|
4
4
|
|
|
@@ -19,12 +19,14 @@ const DropdownInput: React.FC<DropdownInputProps> = ({
|
|
|
19
19
|
onClick,
|
|
20
20
|
className = '',
|
|
21
21
|
options = [],
|
|
22
|
-
onSelect
|
|
22
|
+
onSelect,
|
|
23
23
|
}) => {
|
|
24
24
|
const [isOpen, setIsOpen] = useState(false);
|
|
25
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
26
|
+
|
|
25
27
|
const handleClick = () => {
|
|
26
28
|
if (state === 'disabled' || state === 'loading') return;
|
|
27
|
-
|
|
29
|
+
|
|
28
30
|
setIsOpen(!isOpen);
|
|
29
31
|
onClick?.();
|
|
30
32
|
};
|
|
@@ -54,36 +56,46 @@ const DropdownInput: React.FC<DropdownInputProps> = ({
|
|
|
54
56
|
if (state === 'loading') {
|
|
55
57
|
return <Spinner size="sm" className="dropdown-input__icon" />;
|
|
56
58
|
}
|
|
57
|
-
|
|
59
|
+
|
|
58
60
|
return (
|
|
59
|
-
<Icon
|
|
60
|
-
name={isOpen ? 'chevron-up' : 'chevron-down'}
|
|
61
|
-
size="sm"
|
|
62
|
-
className="dropdown-input__icon dropdown-input__icon--chevron"
|
|
61
|
+
<Icon
|
|
62
|
+
name={isOpen ? 'chevron-up' : 'chevron-down'}
|
|
63
|
+
size="sm"
|
|
64
|
+
className="dropdown-input__icon dropdown-input__icon--chevron"
|
|
63
65
|
/>
|
|
64
66
|
);
|
|
65
67
|
};
|
|
66
68
|
|
|
67
|
-
const displayText = state === 'loading' ? 'Loading...' :
|
|
69
|
+
const displayText = state === 'loading' ? 'Loading...' : value || placeholder;
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
73
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
|
74
|
+
setIsOpen(false);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
79
|
+
|
|
80
|
+
return () => {
|
|
81
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
82
|
+
};
|
|
83
|
+
}, []);
|
|
68
84
|
|
|
69
85
|
return (
|
|
70
|
-
<div className={`dropdown-container ${className}`}>
|
|
71
|
-
<div
|
|
72
|
-
className={`dropdown-input ${getStateClasses()}`}
|
|
73
|
-
onClick={handleClick}
|
|
74
|
-
>
|
|
86
|
+
<div ref={dropdownRef} className={`dropdown-container ${className}`}>
|
|
87
|
+
<div className={`dropdown-input ${getStateClasses()}`} onClick={handleClick}>
|
|
75
88
|
<span className="dropdown-input__text">{displayText}</span>
|
|
76
89
|
{getIcon()}
|
|
77
90
|
</div>
|
|
78
|
-
|
|
91
|
+
|
|
79
92
|
{isOpen && options.length > 0 && (
|
|
80
93
|
<div className="dropdown-menu">
|
|
81
94
|
{options.map((option, index) => (
|
|
82
95
|
<div
|
|
83
96
|
key={index}
|
|
84
97
|
className="dropdown-option"
|
|
85
|
-
onClick={() => handleOptionSelect(option)}
|
|
86
|
-
>
|
|
98
|
+
onClick={() => handleOptionSelect(option)}>
|
|
87
99
|
{option}
|
|
88
100
|
</div>
|
|
89
101
|
))}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Button from '../../atoms/Button/Button';
|
|
3
|
+
import Chip from '../../atoms/Chip/Chip';
|
|
4
|
+
import Icon, { IconName } from '../../atoms/Icon/Icon';
|
|
5
|
+
import { Heading, Text } from '../../atoms/Typography/Typography';
|
|
6
|
+
import TextWithIcon from '../../molecules/TextWithIcon/TextWithIcon';
|
|
7
|
+
import CardContainer from '../CardContainer/CardContainer';
|
|
8
|
+
|
|
9
|
+
export type DocketServiceType =
|
|
10
|
+
| 'Accommodation'
|
|
11
|
+
| 'Transfer'
|
|
12
|
+
| 'Handling fee'
|
|
13
|
+
| 'Excursion'
|
|
14
|
+
| 'Other Services';
|
|
15
|
+
|
|
16
|
+
export interface DocketDetailsData {
|
|
17
|
+
/** Service type */
|
|
18
|
+
type: DocketServiceType;
|
|
19
|
+
/** Service name/title */
|
|
20
|
+
serviceName?: string;
|
|
21
|
+
/** Price for this service */
|
|
22
|
+
price: string;
|
|
23
|
+
/** Currency for the price */
|
|
24
|
+
currency: string;
|
|
25
|
+
/** Start date */
|
|
26
|
+
startDate?: string;
|
|
27
|
+
/** End date */
|
|
28
|
+
endDate?: string;
|
|
29
|
+
/** Number of nights */
|
|
30
|
+
nights?: number;
|
|
31
|
+
/** Client type */
|
|
32
|
+
clientType?: string;
|
|
33
|
+
/** Adults count */
|
|
34
|
+
adults?: number;
|
|
35
|
+
/** Children details */
|
|
36
|
+
children?: Array<{ age: number }>;
|
|
37
|
+
/** Room type */
|
|
38
|
+
roomType?: string;
|
|
39
|
+
/** Meal plan */
|
|
40
|
+
mealPlan?: string;
|
|
41
|
+
/** Additional details to display */
|
|
42
|
+
details?: Array<{
|
|
43
|
+
icon: IconName;
|
|
44
|
+
label: string;
|
|
45
|
+
value: string;
|
|
46
|
+
}>;
|
|
47
|
+
/** Error message to display (e.g., "Please select your second room") */
|
|
48
|
+
errorMessage?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface MultipleQuotationDocketProps {
|
|
52
|
+
/** Title of the quotation */
|
|
53
|
+
title?: string;
|
|
54
|
+
/** List of service details */
|
|
55
|
+
services: DocketDetailsData[];
|
|
56
|
+
/** Total prices in different currencies */
|
|
57
|
+
totalPrices: Array<{ currency: string; amount: string }>;
|
|
58
|
+
/** Callback when "More options" is clicked */
|
|
59
|
+
onMoreOptionsClick?: () => void;
|
|
60
|
+
/** Callback when "Add new quote" is clicked */
|
|
61
|
+
onAddNewQuoteClick?: () => void;
|
|
62
|
+
/** Callback when "View" is clicked */
|
|
63
|
+
onViewClick?: () => void;
|
|
64
|
+
/** Callback when "Save" is clicked */
|
|
65
|
+
onSaveClick?: () => void;
|
|
66
|
+
/** Callback when "Book now" is clicked */
|
|
67
|
+
onBookNowClick?: () => void;
|
|
68
|
+
/** Additional CSS classes */
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const getServiceIcon = (type: DocketServiceType): IconName => {
|
|
73
|
+
switch (type) {
|
|
74
|
+
case 'Accommodation':
|
|
75
|
+
return 'accom';
|
|
76
|
+
case 'Transfer':
|
|
77
|
+
return 'bus';
|
|
78
|
+
case 'Excursion':
|
|
79
|
+
return 'map-pin';
|
|
80
|
+
case 'Handling fee':
|
|
81
|
+
return 'wallet';
|
|
82
|
+
case 'Other Services':
|
|
83
|
+
return 'more';
|
|
84
|
+
default:
|
|
85
|
+
return 'more';
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const DocketDetails: React.FC<{ data: DocketDetailsData }> = ({ data }) => {
|
|
90
|
+
const {
|
|
91
|
+
type,
|
|
92
|
+
serviceName,
|
|
93
|
+
startDate,
|
|
94
|
+
endDate,
|
|
95
|
+
nights,
|
|
96
|
+
clientType,
|
|
97
|
+
adults,
|
|
98
|
+
children,
|
|
99
|
+
roomType,
|
|
100
|
+
mealPlan,
|
|
101
|
+
details,
|
|
102
|
+
errorMessage,
|
|
103
|
+
} = data;
|
|
104
|
+
const icon = getServiceIcon(type);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div className="multiple-quotation-docket__details">
|
|
108
|
+
{errorMessage && (
|
|
109
|
+
<div className="multiple-quotation-docket__error">
|
|
110
|
+
<Text variant="bold" size="sm" color="state-error">
|
|
111
|
+
{errorMessage}
|
|
112
|
+
</Text>
|
|
113
|
+
</div>
|
|
114
|
+
)}
|
|
115
|
+
|
|
116
|
+
{serviceName && (
|
|
117
|
+
<div className="multiple-quotation-docket__service-name">
|
|
118
|
+
<Text variant="bold" size="base">
|
|
119
|
+
{serviceName}
|
|
120
|
+
</Text>
|
|
121
|
+
</div>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
{(startDate || endDate || nights) && (
|
|
125
|
+
<div className="multiple-quotation-docket__date-info">
|
|
126
|
+
{startDate && endDate && (
|
|
127
|
+
<div className="multiple-quotation-docket__date-range">
|
|
128
|
+
<TextWithIcon icon="calendar-range-outline" color="accent">
|
|
129
|
+
{startDate}
|
|
130
|
+
</TextWithIcon>
|
|
131
|
+
<Icon name="arrow-right-outline" size="sm" />
|
|
132
|
+
<TextWithIcon icon="calendar-range-outline" color="accent">
|
|
133
|
+
{endDate}
|
|
134
|
+
</TextWithIcon>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
|
+
{nights !== undefined && (
|
|
138
|
+
<TextWithIcon icon="night" color="subtle">
|
|
139
|
+
{nights} nights
|
|
140
|
+
</TextWithIcon>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
)}
|
|
144
|
+
|
|
145
|
+
{(clientType || adults || children) && (
|
|
146
|
+
<div className="multiple-quotation-docket__client-info">
|
|
147
|
+
{clientType && (
|
|
148
|
+
<div className="multiple-quotation-docket__client-type">
|
|
149
|
+
<Text variant="bold" size="sm" color="subtle">
|
|
150
|
+
Client type:
|
|
151
|
+
</Text>
|
|
152
|
+
<Text variant="medium" size="sm" color="subtle">
|
|
153
|
+
{clientType}
|
|
154
|
+
</Text>
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
157
|
+
|
|
158
|
+
<div className="multiple-quotation-docket__guests">
|
|
159
|
+
{adults !== undefined && (
|
|
160
|
+
<TextWithIcon icon="user" color="subtle">
|
|
161
|
+
{adults} Adults
|
|
162
|
+
</TextWithIcon>
|
|
163
|
+
)}
|
|
164
|
+
{children && children.length > 0 && (
|
|
165
|
+
<div className="multiple-quotation-docket__children">
|
|
166
|
+
{children.map((child, index) => (
|
|
167
|
+
<div key={index} className="multiple-quotation-docket__child">
|
|
168
|
+
<TextWithIcon icon="user" color="subtle">
|
|
169
|
+
<span>
|
|
170
|
+
<span>1 Child </span>
|
|
171
|
+
<span className="multiple-quotation-docket__child-age">
|
|
172
|
+
({child.age} y.o)
|
|
173
|
+
</span>
|
|
174
|
+
</span>
|
|
175
|
+
</TextWithIcon>
|
|
176
|
+
{index < children.length - 1 && (
|
|
177
|
+
<div className="multiple-quotation-docket__divider" />
|
|
178
|
+
)}
|
|
179
|
+
</div>
|
|
180
|
+
))}
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
)}
|
|
186
|
+
|
|
187
|
+
{(roomType || mealPlan) && (
|
|
188
|
+
<div className="multiple-quotation-docket__room-info">
|
|
189
|
+
{roomType && (
|
|
190
|
+
<TextWithIcon icon="accom" color="subtle">
|
|
191
|
+
{roomType}
|
|
192
|
+
</TextWithIcon>
|
|
193
|
+
)}
|
|
194
|
+
{mealPlan && (
|
|
195
|
+
<div className="multiple-quotation-docket__meal-plan">
|
|
196
|
+
<TextWithIcon icon="utensils" color="subtle">
|
|
197
|
+
Meal-Plan
|
|
198
|
+
</TextWithIcon>
|
|
199
|
+
<div className="multiple-quotation-docket__divider" />
|
|
200
|
+
<Text variant="medium" size="sm" color="subtle">
|
|
201
|
+
{mealPlan}
|
|
202
|
+
</Text>
|
|
203
|
+
</div>
|
|
204
|
+
)}
|
|
205
|
+
</div>
|
|
206
|
+
)}
|
|
207
|
+
|
|
208
|
+
{details && details.length > 0 && (
|
|
209
|
+
<div className="multiple-quotation-docket__additional-details">
|
|
210
|
+
{details.map((detail, index) => (
|
|
211
|
+
<TextWithIcon key={index} icon={detail.icon} color="subtle">
|
|
212
|
+
{detail.label}: {detail.value}
|
|
213
|
+
</TextWithIcon>
|
|
214
|
+
))}
|
|
215
|
+
</div>
|
|
216
|
+
)}
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export const MultipleQuotationDocket: React.FC<MultipleQuotationDocketProps> = ({
|
|
222
|
+
title = 'Your quotation',
|
|
223
|
+
services,
|
|
224
|
+
totalPrices,
|
|
225
|
+
onMoreOptionsClick,
|
|
226
|
+
onAddNewQuoteClick,
|
|
227
|
+
onViewClick,
|
|
228
|
+
onSaveClick,
|
|
229
|
+
onBookNowClick,
|
|
230
|
+
className = '',
|
|
231
|
+
}) => {
|
|
232
|
+
return (
|
|
233
|
+
<CardContainer spacing="chill" className={`multiple-quotation-docket ${className}`}>
|
|
234
|
+
{/* Header */}
|
|
235
|
+
<div className="multiple-quotation-docket__header">
|
|
236
|
+
<div className="multiple-quotation-docket__title">
|
|
237
|
+
<Icon name="quotation" size="lg" />
|
|
238
|
+
<Heading
|
|
239
|
+
level={4}
|
|
240
|
+
variant="bold"
|
|
241
|
+
className="multiple-quotation-docket__title-text">
|
|
242
|
+
{title}
|
|
243
|
+
</Heading>
|
|
244
|
+
</div>
|
|
245
|
+
{onMoreOptionsClick && (
|
|
246
|
+
<Chip
|
|
247
|
+
type="outline"
|
|
248
|
+
color="neutral"
|
|
249
|
+
size="sm"
|
|
250
|
+
trailingIcon="chevron-down"
|
|
251
|
+
onClick={onMoreOptionsClick}
|
|
252
|
+
className="multiple-quotation-docket__more-options">
|
|
253
|
+
More options
|
|
254
|
+
</Chip>
|
|
255
|
+
)}
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
{/* Services List */}
|
|
259
|
+
<div className="multiple-quotation-docket__services">
|
|
260
|
+
{services.map((service, index) => (
|
|
261
|
+
<div key={index} className="multiple-quotation-docket__service">
|
|
262
|
+
<div className="multiple-quotation-docket__service-header">
|
|
263
|
+
<div className="multiple-quotation-docket__service-title">
|
|
264
|
+
<div className="multiple-quotation-docket__section-bar" />
|
|
265
|
+
<Icon
|
|
266
|
+
name={getServiceIcon(service.type)}
|
|
267
|
+
size="sm"
|
|
268
|
+
color="var(--color-icon-branded, #0f7173)"
|
|
269
|
+
/>
|
|
270
|
+
<Text variant="bold" size="sm" color="accent">
|
|
271
|
+
{service.type}
|
|
272
|
+
</Text>
|
|
273
|
+
</div>
|
|
274
|
+
<Chip type="filled" color="accent" size="sm">
|
|
275
|
+
{service.currency} {service.price}
|
|
276
|
+
</Chip>
|
|
277
|
+
</div>
|
|
278
|
+
<DocketDetails data={service} />
|
|
279
|
+
</div>
|
|
280
|
+
))}
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
{/* Total Section */}
|
|
284
|
+
{totalPrices.length > 0 && (
|
|
285
|
+
<div className="multiple-quotation-docket__total">
|
|
286
|
+
<div className="multiple-quotation-docket__total-line" />
|
|
287
|
+
<div className="multiple-quotation-docket__total-content">
|
|
288
|
+
<Text variant="bold" size="sm">
|
|
289
|
+
Total :
|
|
290
|
+
</Text>
|
|
291
|
+
<div className="multiple-quotation-docket__total-prices">
|
|
292
|
+
{totalPrices.map((total, index) => (
|
|
293
|
+
<Text key={index} variant="bold" size="sm">
|
|
294
|
+
{total.currency} {total.amount}
|
|
295
|
+
</Text>
|
|
296
|
+
))}
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
<div className="multiple-quotation-docket__total-line" />
|
|
300
|
+
</div>
|
|
301
|
+
)}
|
|
302
|
+
|
|
303
|
+
{/* Actions */}
|
|
304
|
+
<div className="multiple-quotation-docket__actions">
|
|
305
|
+
{onAddNewQuoteClick && (
|
|
306
|
+
<Button
|
|
307
|
+
variant="outline-secondary"
|
|
308
|
+
size="sm"
|
|
309
|
+
leadingIcon="plus"
|
|
310
|
+
onClick={onAddNewQuoteClick}
|
|
311
|
+
className="multiple-quotation-docket__action-button">
|
|
312
|
+
Add new quote
|
|
313
|
+
</Button>
|
|
314
|
+
)}
|
|
315
|
+
<div className="multiple-quotation-docket__action-group">
|
|
316
|
+
{onViewClick && (
|
|
317
|
+
<Button
|
|
318
|
+
variant="outline-secondary"
|
|
319
|
+
size="sm"
|
|
320
|
+
onClick={onViewClick}
|
|
321
|
+
className="multiple-quotation-docket__action-button multiple-quotation-docket__action-button--flex">
|
|
322
|
+
View
|
|
323
|
+
</Button>
|
|
324
|
+
)}
|
|
325
|
+
{onSaveClick && (
|
|
326
|
+
<Button
|
|
327
|
+
variant="outline-secondary"
|
|
328
|
+
size="sm"
|
|
329
|
+
onClick={onSaveClick}
|
|
330
|
+
className="multiple-quotation-docket__action-button multiple-quotation-docket__action-button--flex">
|
|
331
|
+
Save
|
|
332
|
+
</Button>
|
|
333
|
+
)}
|
|
334
|
+
{onBookNowClick && (
|
|
335
|
+
<Button
|
|
336
|
+
variant="primary"
|
|
337
|
+
size="sm"
|
|
338
|
+
onClick={onBookNowClick}
|
|
339
|
+
className="multiple-quotation-docket__action-button multiple-quotation-docket__action-button--book">
|
|
340
|
+
Book now
|
|
341
|
+
</Button>
|
|
342
|
+
)}
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
</CardContainer>
|
|
346
|
+
);
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export default MultipleQuotationDocket;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.quote-header {
|
|
2
|
+
@apply w-full;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.quote-header__button {
|
|
6
|
+
width: 206px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.quote-header__title {
|
|
10
|
+
@apply px-2 relative mb-10;
|
|
11
|
+
&::before {
|
|
12
|
+
content: '';
|
|
13
|
+
@apply absolute top-1/2 left-0 -translate-y-1/2;
|
|
14
|
+
@apply w-1 h-8;
|
|
15
|
+
background-color: var(--color-elevation-brand-subtle);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.quote-header__search-container {
|
|
20
|
+
@apply mt-12;
|
|
21
|
+
@apply flex justify-between;
|
|
22
|
+
> button {
|
|
23
|
+
@apply gap-x-2.5;
|
|
24
|
+
min-width: 129px;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.quote-header__search {
|
|
29
|
+
width: 364px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.quote-header__filters {
|
|
33
|
+
@apply flex gap-3 my-8;
|
|
34
|
+
.dropdown-container {
|
|
35
|
+
width: 139px;
|
|
36
|
+
}
|
|
37
|
+
}
|