mautourco-components 0.2.14 → 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/registry.d.ts +1 -0
- package/dist/components/atoms/Icon/icons/registry.js +2 -0
- package/dist/components/atoms/Inputs/DropdownInput/DropdownInput.js +15 -3
- 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 +2 -0
- package/dist/index.js +1 -0
- package/dist/styles/components/dropdown.css +7 -6
- package/dist/styles/components/forms.css +18 -9
- package/package.json +1 -1
- package/src/components/atoms/Icon/icons/PlusCircleIcon.tsx +60 -0
- package/src/components/atoms/Icon/icons/registry.tsx +2 -0
- package/src/components/atoms/Inputs/DropdownInput/DropdownInput.tsx +29 -17
- 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
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './QuoteHeader.css';
|
|
3
|
+
export interface QuoteHeaderProps {
|
|
4
|
+
/** Current tab */
|
|
5
|
+
current: 'quotation' | 'booking';
|
|
6
|
+
/** Callback to navigate to a different tab */
|
|
7
|
+
onNavigate: (tab: 'quotation' | 'booking') => void;
|
|
8
|
+
/** Callback to create a new quote */
|
|
9
|
+
onNewQuote: () => void;
|
|
10
|
+
onFilterChange: (filter: 'date' | 'clientType' | 'fileStatus', value: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const QuoteHeader: React.FC<QuoteHeaderProps>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import Button from '../../atoms/Button/Button';
|
|
14
|
+
import DropdownInput from '../../atoms/Inputs/DropdownInput/DropdownInput';
|
|
15
|
+
import Input from '../../atoms/Inputs/Input/Input';
|
|
16
|
+
import { Heading } from '../../atoms/Typography/Typography';
|
|
17
|
+
import { SORT_BY__FILE_STATUS_OPTIONS, SORT_BY_CLIENT_TYPE_OPTIONS, SORT_BY_DATE_OPTIONS, } from './constant';
|
|
18
|
+
import './QuoteHeader.css';
|
|
19
|
+
var filterConfig = {
|
|
20
|
+
date: {
|
|
21
|
+
options: SORT_BY_DATE_OPTIONS,
|
|
22
|
+
placeholder: 'Sort by date',
|
|
23
|
+
},
|
|
24
|
+
clientType: {
|
|
25
|
+
options: SORT_BY_CLIENT_TYPE_OPTIONS,
|
|
26
|
+
placeholder: 'Client type',
|
|
27
|
+
},
|
|
28
|
+
fileStatus: {
|
|
29
|
+
options: SORT_BY__FILE_STATUS_OPTIONS,
|
|
30
|
+
placeholder: 'File status',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
export var QuoteHeader = function (props) {
|
|
34
|
+
var _a = props.current, current = _a === void 0 ? 'quotation' : _a, onNavigate = props.onNavigate, onNewQuote = props.onNewQuote, onFilterChange = props.onFilterChange;
|
|
35
|
+
return (_jsxs("div", __assign({ className: "quote-header" }, { children: [_jsx(Heading, __assign({ level: 4, as: "h1", className: "quote-header__title", color: "accent" }, { children: "Quotation & Booking" })), _jsxs("div", __assign({ className: "flex gap-4" }, { children: [_jsx(Button, __assign({ variant: current === 'quotation' ? 'primary' : 'outline-primary', className: "quote-header__button", onClick: function () { return onNavigate('quotation'); } }, { children: "Quotation" })), _jsx(Button, __assign({ variant: current === 'booking' ? 'primary' : 'outline-primary', className: "quote-header__button", onClick: function () { return onNavigate('booking'); } }, { children: "Booking" }))] })), _jsxs("div", __assign({ className: "quote-header__search-container" }, { children: [_jsx(Input, { placeholder: "Search", icon: "search", iconPosition: "leading", className: "quote-header__search" }), _jsx(Button, __assign({ variant: "primary", leadingIcon: "plus-circle", iconSize: "md", size: "sm", onClick: onNewQuote }, { children: "New quote" }))] })), _jsx("div", __assign({ className: "quote-header__filters" }, { children: Object.entries(filterConfig).map(function (_a) {
|
|
36
|
+
var key = _a[0], value = _a[1];
|
|
37
|
+
return (_jsx(DropdownInput, { placeholder: value.placeholder, options: value.options, onSelect: function (value) {
|
|
38
|
+
return onFilterChange(key, value);
|
|
39
|
+
} }, key));
|
|
40
|
+
}) }))] })));
|
|
41
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export var SORT_BY_DATE_OPTIONS = ['Newest to oldest', 'Last week', 'Oldest to newest'];
|
|
2
|
+
export var SORT_BY_CLIENT_TYPE_OPTIONS = ['All', 'Standard', 'Honeymoon', 'Wedding'];
|
|
3
|
+
export var SORT_BY__FILE_STATUS_OPTIONS = [
|
|
4
|
+
'All',
|
|
5
|
+
'Free sales',
|
|
6
|
+
'On request',
|
|
7
|
+
'Pay to book',
|
|
8
|
+
];
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export { Dialog } from './components/organisms/Dialog/Dialog';
|
|
|
35
35
|
export { Footer } from './components/organisms/Footer/Footer';
|
|
36
36
|
export { default as MultipleQuotationDocket } from './components/organisms/MultipleQuotationDocket';
|
|
37
37
|
export { default as PaxSelector } from './components/organisms/PaxSelector/PaxSelector';
|
|
38
|
+
export { QuoteHeader } from './components/organisms/QuoteHeader/QuoteHeader';
|
|
38
39
|
export { default as RoundTrip } from './components/organisms/RoundTrip/RoundTrip';
|
|
39
40
|
export { default as SearchBarTransfer } from './components/organisms/SearchBarTransfer/SearchBarTransfer';
|
|
40
41
|
export * from './components/organisms/Table';
|
|
@@ -70,4 +71,5 @@ export type { TransferLineData, TransferLineProps, TransferType, } from './compo
|
|
|
70
71
|
export type { FromToProps } from './components/molecules/FromTo/FromTo';
|
|
71
72
|
export type { SectionTitleProps } from './components/molecules/SectionTitle/SectionTitle';
|
|
72
73
|
export type { DetailsColProps, ItemColProps, RowAccommodationProps, RowExcursionProps, RowTransferProps, } from './components/molecules/TableServiceItem';
|
|
74
|
+
export type { QuoteHeaderProps } from './components/organisms/QuoteHeader/QuoteHeader';
|
|
73
75
|
export * from './types/table';
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ export { Dialog } from './components/organisms/Dialog/Dialog';
|
|
|
38
38
|
export { Footer } from './components/organisms/Footer/Footer';
|
|
39
39
|
export { default as MultipleQuotationDocket } from './components/organisms/MultipleQuotationDocket';
|
|
40
40
|
export { default as PaxSelector } from './components/organisms/PaxSelector/PaxSelector';
|
|
41
|
+
export { QuoteHeader } from './components/organisms/QuoteHeader/QuoteHeader';
|
|
41
42
|
export { default as RoundTrip } from './components/organisms/RoundTrip/RoundTrip';
|
|
42
43
|
export { default as SearchBarTransfer } from './components/organisms/SearchBarTransfer/SearchBarTransfer';
|
|
43
44
|
export * from './components/organisms/Table';
|
|
@@ -2089,8 +2089,8 @@
|
|
|
2089
2089
|
width: 100%;
|
|
2090
2090
|
min-height: 40px;
|
|
2091
2091
|
padding: 8px 12px;
|
|
2092
|
-
border: 1px solid var(--color-slate-500, #
|
|
2093
|
-
border-radius:
|
|
2092
|
+
border: 1px solid var(--color-slate-500, #6b7280);
|
|
2093
|
+
border-radius: var(--input-border-radius-default);
|
|
2094
2094
|
background-color: var(--color-white, #ffffff);
|
|
2095
2095
|
cursor: pointer;
|
|
2096
2096
|
transition: all 0.2s ease-in-out;
|
|
@@ -2161,7 +2161,7 @@
|
|
|
2161
2161
|
|
|
2162
2162
|
.dropdown-input--disabled {
|
|
2163
2163
|
background-color: var(--color-slate-100);
|
|
2164
|
-
border-color: var(--color-slate-300, #
|
|
2164
|
+
border-color: var(--color-slate-300, #d1d5db);
|
|
2165
2165
|
cursor: not-allowed;
|
|
2166
2166
|
}
|
|
2167
2167
|
|
|
@@ -2183,10 +2183,11 @@
|
|
|
2183
2183
|
z-index: 1000;
|
|
2184
2184
|
width: 100%;
|
|
2185
2185
|
background-color: var(--color-white);
|
|
2186
|
-
border: 1px solid var(--color-
|
|
2187
|
-
border-top: 1px solid var(--color-neutral-400);
|
|
2186
|
+
border: 1px solid var(--color-border-subtle);
|
|
2188
2187
|
border-radius: var(--multiselect-border-radius, 0.75rem);
|
|
2189
|
-
box-shadow:
|
|
2188
|
+
box-shadow:
|
|
2189
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
2190
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
2190
2191
|
max-height: var(--multiselect-size-menu-max-height, 17.25rem);
|
|
2191
2192
|
overflow-y: auto;
|
|
2192
2193
|
padding: var(--spacing-padding-px-0);
|
|
@@ -2077,10 +2077,10 @@
|
|
|
2077
2077
|
/* Styles Input centralisés: consomment uniquement des variables CSS issues de Style Dictionary */
|
|
2078
2078
|
|
|
2079
2079
|
.input-field {
|
|
2080
|
-
font-family: var(--typography-font-family-sans, Inter,system-ui,sans-serif);
|
|
2080
|
+
font-family: var(--typography-font-family-sans, Inter, system-ui, sans-serif);
|
|
2081
2081
|
font-size: var(--input-font-size-default, 1rem);
|
|
2082
2082
|
line-height: var(--input-line-height-default, 1.5rem);
|
|
2083
|
-
border-radius:
|
|
2083
|
+
border-radius: var(--input-border-radius-default);
|
|
2084
2084
|
border-width: 1px;
|
|
2085
2085
|
border-style: solid;
|
|
2086
2086
|
padding: var(--input-padding-vertical, 0.5rem) var(--input-padding-horizontal, 0.75rem);
|
|
@@ -2095,6 +2095,7 @@
|
|
|
2095
2095
|
.input-wrapper {
|
|
2096
2096
|
position: relative;
|
|
2097
2097
|
width: 100%;
|
|
2098
|
+
height: 42px;
|
|
2098
2099
|
}
|
|
2099
2100
|
|
|
2100
2101
|
.input-icon {
|
|
@@ -2106,16 +2107,24 @@
|
|
|
2106
2107
|
height: var(--input-search-iconSize, 1rem);
|
|
2107
2108
|
}
|
|
2108
2109
|
|
|
2109
|
-
.input-icon--leading {
|
|
2110
|
+
.input-icon--leading {
|
|
2111
|
+
left: var(--input-padding-horizontal, 0.75rem);
|
|
2112
|
+
}
|
|
2110
2113
|
|
|
2111
|
-
.input-icon--trailing {
|
|
2114
|
+
.input-icon--trailing {
|
|
2115
|
+
right: var(--input-padding-horizontal, 0.75rem);
|
|
2116
|
+
}
|
|
2112
2117
|
|
|
2113
2118
|
.input-field--with-icon.input-field--icon-leading {
|
|
2114
|
-
padding-left: calc(
|
|
2119
|
+
padding-left: calc(
|
|
2120
|
+
var(--input-padding-horizontal, 0.75rem) + var(--input-search-iconSize, 1rem) + 0.5rem
|
|
2121
|
+
);
|
|
2115
2122
|
}
|
|
2116
2123
|
|
|
2117
2124
|
.input-field--with-icon.input-field--icon-trailing {
|
|
2118
|
-
padding-right: calc(
|
|
2125
|
+
padding-right: calc(
|
|
2126
|
+
var(--input-padding-horizontal, 0.75rem) + var(--input-search-iconSize, 1rem) + 0.5rem
|
|
2127
|
+
);
|
|
2119
2128
|
}
|
|
2120
2129
|
|
|
2121
2130
|
.input-field:focus {
|
|
@@ -2126,7 +2135,7 @@
|
|
|
2126
2135
|
|
|
2127
2136
|
.input-field--default {
|
|
2128
2137
|
background-color: var(--color-white);
|
|
2129
|
-
border-color: var(--color-
|
|
2138
|
+
border-color: var(--color-tuna-500);
|
|
2130
2139
|
color: var(--color-slate-900);
|
|
2131
2140
|
}
|
|
2132
2141
|
|
|
@@ -2194,7 +2203,7 @@
|
|
|
2194
2203
|
}
|
|
2195
2204
|
|
|
2196
2205
|
.input-showcase h1 {
|
|
2197
|
-
font-family: var(--typography-font-family-sans, Inter,system-ui,sans-serif);
|
|
2206
|
+
font-family: var(--typography-font-family-sans, Inter, system-ui, sans-serif);
|
|
2198
2207
|
font-size: var(--typography-font-size-2xl, 1.5re);
|
|
2199
2208
|
font-weight: var(--font-weight-font-bold);
|
|
2200
2209
|
color: var(--color-slate-900);
|
|
@@ -2202,7 +2211,7 @@
|
|
|
2202
2211
|
}
|
|
2203
2212
|
|
|
2204
2213
|
.input-showcase h2 {
|
|
2205
|
-
font-family: var(--typography-font-family-sans, Inter,system-ui,sans-serif);
|
|
2214
|
+
font-family: var(--typography-font-family-sans, Inter, system-ui, sans-serif);
|
|
2206
2215
|
font-size: var(--typography-font-size-lg, 1.125rem);
|
|
2207
2216
|
font-weight: var(--font-weight-font-medium);
|
|
2208
2217
|
color: var(--color-slate-700);
|
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;
|
|
@@ -35,6 +35,7 @@ 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';
|
|
39
40
|
import QuotationIcon from './QuotationIcon';
|
|
40
41
|
import Search from './Search';
|
|
@@ -124,6 +125,7 @@ export const ICONS = {
|
|
|
124
125
|
bus: BusIcon as unknown as IconComponent,
|
|
125
126
|
map: MapIcon as unknown as IconComponent,
|
|
126
127
|
wallet: WalletIcon as unknown as IconComponent,
|
|
128
|
+
'plus-circle': PlusCircleIcon as unknown as IconComponent,
|
|
127
129
|
} as const satisfies Record<string, IconComponent>;
|
|
128
130
|
|
|
129
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,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
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Button from '../../atoms/Button/Button';
|
|
3
|
+
import DropdownInput from '../../atoms/Inputs/DropdownInput/DropdownInput';
|
|
4
|
+
import Input from '../../atoms/Inputs/Input/Input';
|
|
5
|
+
import { Heading } from '../../atoms/Typography/Typography';
|
|
6
|
+
import {
|
|
7
|
+
SORT_BY__FILE_STATUS_OPTIONS,
|
|
8
|
+
SORT_BY_CLIENT_TYPE_OPTIONS,
|
|
9
|
+
SORT_BY_DATE_OPTIONS,
|
|
10
|
+
} from './constant';
|
|
11
|
+
import './QuoteHeader.css';
|
|
12
|
+
|
|
13
|
+
export interface QuoteHeaderProps {
|
|
14
|
+
/** Current tab */
|
|
15
|
+
current: 'quotation' | 'booking';
|
|
16
|
+
|
|
17
|
+
/** Callback to navigate to a different tab */
|
|
18
|
+
onNavigate: (tab: 'quotation' | 'booking') => void;
|
|
19
|
+
|
|
20
|
+
/** Callback to create a new quote */
|
|
21
|
+
onNewQuote: () => void;
|
|
22
|
+
|
|
23
|
+
onFilterChange: (filter: 'date' | 'clientType' | 'fileStatus', value: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const filterConfig = {
|
|
27
|
+
date: {
|
|
28
|
+
options: SORT_BY_DATE_OPTIONS,
|
|
29
|
+
placeholder: 'Sort by date',
|
|
30
|
+
},
|
|
31
|
+
clientType: {
|
|
32
|
+
options: SORT_BY_CLIENT_TYPE_OPTIONS,
|
|
33
|
+
placeholder: 'Client type',
|
|
34
|
+
},
|
|
35
|
+
fileStatus: {
|
|
36
|
+
options: SORT_BY__FILE_STATUS_OPTIONS,
|
|
37
|
+
placeholder: 'File status',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const QuoteHeader: React.FC<QuoteHeaderProps> = (props) => {
|
|
42
|
+
const { current = 'quotation', onNavigate, onNewQuote, onFilterChange } = props;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="quote-header">
|
|
46
|
+
<Heading level={4} as="h1" className="quote-header__title" color="accent">
|
|
47
|
+
Quotation & Booking
|
|
48
|
+
</Heading>
|
|
49
|
+
<div className="flex gap-4">
|
|
50
|
+
<Button
|
|
51
|
+
variant={current === 'quotation' ? 'primary' : 'outline-primary'}
|
|
52
|
+
className="quote-header__button"
|
|
53
|
+
onClick={() => onNavigate('quotation')}>
|
|
54
|
+
Quotation
|
|
55
|
+
</Button>
|
|
56
|
+
<Button
|
|
57
|
+
variant={current === 'booking' ? 'primary' : 'outline-primary'}
|
|
58
|
+
className="quote-header__button"
|
|
59
|
+
onClick={() => onNavigate('booking')}>
|
|
60
|
+
Booking
|
|
61
|
+
</Button>
|
|
62
|
+
</div>
|
|
63
|
+
<div className="quote-header__search-container">
|
|
64
|
+
<Input
|
|
65
|
+
placeholder="Search"
|
|
66
|
+
icon="search"
|
|
67
|
+
iconPosition="leading"
|
|
68
|
+
className="quote-header__search"
|
|
69
|
+
/>
|
|
70
|
+
<Button
|
|
71
|
+
variant="primary"
|
|
72
|
+
leadingIcon="plus-circle"
|
|
73
|
+
iconSize="md"
|
|
74
|
+
size="sm"
|
|
75
|
+
onClick={onNewQuote}>
|
|
76
|
+
New quote
|
|
77
|
+
</Button>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="quote-header__filters">
|
|
80
|
+
{Object.entries(filterConfig).map(([key, value]) => (
|
|
81
|
+
<DropdownInput
|
|
82
|
+
key={key}
|
|
83
|
+
placeholder={value.placeholder}
|
|
84
|
+
options={value.options}
|
|
85
|
+
onSelect={(value) =>
|
|
86
|
+
onFilterChange(key as 'date' | 'clientType' | 'fileStatus', value)
|
|
87
|
+
}
|
|
88
|
+
/>
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const SORT_BY_DATE_OPTIONS = ['Newest to oldest', 'Last week', 'Oldest to newest'];
|
|
2
|
+
export const SORT_BY_CLIENT_TYPE_OPTIONS = ['All', 'Standard', 'Honeymoon', 'Wedding'];
|
|
3
|
+
export const SORT_BY__FILE_STATUS_OPTIONS = [
|
|
4
|
+
'All',
|
|
5
|
+
'Free sales',
|
|
6
|
+
'On request',
|
|
7
|
+
'Pay to book',
|
|
8
|
+
];
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
width: 100%;
|
|
13
13
|
min-height: 40px;
|
|
14
14
|
padding: 8px 12px;
|
|
15
|
-
border: 1px solid var(--color-slate-500, #
|
|
16
|
-
border-radius:
|
|
15
|
+
border: 1px solid var(--color-slate-500, #6b7280);
|
|
16
|
+
border-radius: var(--input-border-radius-default);
|
|
17
17
|
background-color: var(--color-white, #ffffff);
|
|
18
18
|
cursor: pointer;
|
|
19
19
|
transition: all 0.2s ease-in-out;
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
|
|
84
84
|
.dropdown-input--disabled {
|
|
85
85
|
background-color: var(--color-slate-100);
|
|
86
|
-
border-color: var(--color-slate-300, #
|
|
86
|
+
border-color: var(--color-slate-300, #d1d5db);
|
|
87
87
|
cursor: not-allowed;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -104,10 +104,11 @@
|
|
|
104
104
|
z-index: 1000;
|
|
105
105
|
width: 100%;
|
|
106
106
|
background-color: var(--color-white);
|
|
107
|
-
border: 1px solid var(--color-
|
|
108
|
-
border-top: 1px solid var(--color-neutral-400);
|
|
107
|
+
border: 1px solid var(--color-border-subtle);
|
|
109
108
|
border-radius: var(--multiselect-border-radius, 0.75rem);
|
|
110
|
-
box-shadow:
|
|
109
|
+
box-shadow:
|
|
110
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
111
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
111
112
|
max-height: var(--multiselect-size-menu-max-height, 17.25rem);
|
|
112
113
|
overflow-y: auto;
|
|
113
114
|
padding: var(--spacing-padding-px-0);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* Styles Input centralisés: consomment uniquement des variables CSS issues de Style Dictionary */
|
|
2
2
|
|
|
3
3
|
.input-field {
|
|
4
|
-
font-family: var(--typography-font-family-sans, Inter,system-ui,sans-serif);
|
|
4
|
+
font-family: var(--typography-font-family-sans, Inter, system-ui, sans-serif);
|
|
5
5
|
font-size: var(--input-font-size-default, 1rem);
|
|
6
6
|
line-height: var(--input-line-height-default, 1.5rem);
|
|
7
|
-
border-radius:
|
|
7
|
+
border-radius: var(--input-border-radius-default);
|
|
8
8
|
border-width: 1px;
|
|
9
9
|
border-style: solid;
|
|
10
10
|
padding: var(--input-padding-vertical, 0.5rem) var(--input-padding-horizontal, 0.75rem);
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
.input-wrapper {
|
|
19
19
|
position: relative;
|
|
20
20
|
width: 100%;
|
|
21
|
+
height: 42px;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
.input-icon {
|
|
@@ -29,15 +30,23 @@
|
|
|
29
30
|
height: var(--input-search-iconSize, 1rem);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
.input-icon--leading {
|
|
33
|
-
|
|
33
|
+
.input-icon--leading {
|
|
34
|
+
left: var(--input-padding-horizontal, 0.75rem);
|
|
35
|
+
}
|
|
36
|
+
.input-icon--trailing {
|
|
37
|
+
right: var(--input-padding-horizontal, 0.75rem);
|
|
38
|
+
}
|
|
34
39
|
|
|
35
40
|
.input-field--with-icon.input-field--icon-leading {
|
|
36
|
-
padding-left: calc(
|
|
41
|
+
padding-left: calc(
|
|
42
|
+
var(--input-padding-horizontal, 0.75rem) + var(--input-search-iconSize, 1rem) + 0.5rem
|
|
43
|
+
);
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
.input-field--with-icon.input-field--icon-trailing {
|
|
40
|
-
padding-right: calc(
|
|
47
|
+
padding-right: calc(
|
|
48
|
+
var(--input-padding-horizontal, 0.75rem) + var(--input-search-iconSize, 1rem) + 0.5rem
|
|
49
|
+
);
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
.input-field:focus {
|
|
@@ -47,7 +56,7 @@
|
|
|
47
56
|
/* État par défaut */
|
|
48
57
|
.input-field--default {
|
|
49
58
|
background-color: var(--color-white);
|
|
50
|
-
border-color: var(--color-
|
|
59
|
+
border-color: var(--color-tuna-500);
|
|
51
60
|
color: var(--color-slate-900);
|
|
52
61
|
}
|
|
53
62
|
|
|
@@ -110,7 +119,7 @@
|
|
|
110
119
|
}
|
|
111
120
|
|
|
112
121
|
.input-showcase h1 {
|
|
113
|
-
font-family: var(--typography-font-family-sans, Inter,system-ui,sans-serif);
|
|
122
|
+
font-family: var(--typography-font-family-sans, Inter, system-ui, sans-serif);
|
|
114
123
|
font-size: var(--typography-font-size-2xl, 1.5re);
|
|
115
124
|
font-weight: var(--font-weight-font-bold);
|
|
116
125
|
color: var(--color-slate-900);
|
|
@@ -118,7 +127,7 @@
|
|
|
118
127
|
}
|
|
119
128
|
|
|
120
129
|
.input-showcase h2 {
|
|
121
|
-
font-family: var(--typography-font-family-sans, Inter,system-ui,sans-serif);
|
|
130
|
+
font-family: var(--typography-font-family-sans, Inter, system-ui, sans-serif);
|
|
122
131
|
font-size: var(--typography-font-size-lg, 1.125rem);
|
|
123
132
|
font-weight: var(--font-weight-font-medium);
|
|
124
133
|
color: var(--color-slate-700);
|
|
@@ -143,5 +152,3 @@
|
|
|
143
152
|
width: 100%;
|
|
144
153
|
max-width: 300px;
|
|
145
154
|
}
|
|
146
|
-
|
|
147
|
-
|