mautourco-components 0.2.142 → 0.2.144

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.
Files changed (24) hide show
  1. package/dist/components/molecules/LanguageSelector/LanguageSelector.css +120 -0
  2. package/dist/components/molecules/LanguageSelector/LanguageSelector.d.ts +11 -0
  3. package/dist/components/molecules/LanguageSelector/LanguageSelector.js +28 -0
  4. package/dist/components/molecules/TextWithIcon/TextWithIcon.js +1 -1
  5. package/dist/components/organisms/Docket/Docket.d.ts +31 -6
  6. package/dist/components/organisms/Docket/Docket.js +33 -13
  7. package/dist/components/organisms/Docket/DocketEmptyState.d.ts +14 -3
  8. package/dist/components/organisms/Docket/DocketEmptyState.js +7 -2
  9. package/dist/components/organisms/Docket/DocketFooter.d.ts +24 -0
  10. package/dist/components/organisms/Docket/DocketFooter.js +11 -3
  11. package/dist/components/organisms/DocketAccordion/DocketAccordion.d.ts +10 -1
  12. package/dist/components/organisms/DocketAccordion/DocketAccordion.js +2 -2
  13. package/dist/hooks/useMobile.d.ts +2 -1
  14. package/dist/hooks/useMobile.js +1 -0
  15. package/dist/styles/components/organism/docket.css +14 -20
  16. package/package.json +1 -1
  17. package/src/components/molecules/LanguageSelector/LanguageSelector.css +83 -0
  18. package/src/components/molecules/LanguageSelector/LanguageSelector.tsx +102 -0
  19. package/src/components/molecules/TextWithIcon/TextWithIcon.tsx +1 -1
  20. package/src/components/organisms/Docket/Docket.tsx +106 -24
  21. package/src/components/organisms/Docket/DocketEmptyState.tsx +29 -7
  22. package/src/components/organisms/Docket/DocketFooter.tsx +82 -26
  23. package/src/components/organisms/DocketAccordion/DocketAccordion.tsx +12 -2
  24. package/src/styles/components/organism/docket.css +13 -20
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+
5
+ /* Language Selector - Trigger */
6
+ .language-selector__trigger {
7
+ display: flex;
8
+ cursor: pointer;
9
+ align-items: center;
10
+ justify-content: center;
11
+ gap: 0.5rem;
12
+ padding-left: 1rem;
13
+ padding-right: 1rem;
14
+ height: 44px;
15
+ border: solid 1px var(--color-tuna-500);
16
+ border-radius: 12px;
17
+ transition: all 0.5s ease;
18
+ &:hover {
19
+ border-color: #262626;
20
+ }
21
+ &.language-selector__trigger--with-text {
22
+ border-color: #262626;
23
+ color: #262626;
24
+ }
25
+ }
26
+
27
+ .language-selector__placeholder {
28
+ color: var(--color-tuna-500);
29
+ }
30
+
31
+ .language-selector__trigger-icon {
32
+ flex-shrink: 0;
33
+ color: var(--color-neutral-800);
34
+ }
35
+
36
+ .language-selector__trigger-text {
37
+ font-size: 0.875rem;
38
+ line-height: 1.25rem;
39
+ font-weight: 500;
40
+ color: var(--color-neutral-800);
41
+ }
42
+
43
+ .language-selector__trigger-chevron {
44
+ flex-shrink: 0;
45
+ color: var(--color-neutral-800);
46
+ transition-property: transform;
47
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
48
+ transition-duration: 200ms;
49
+ }
50
+
51
+ .language-selector__trigger[data-state='open'] .language-selector__trigger-chevron {
52
+ transform: rotate(180deg);
53
+ }
54
+
55
+ /* Popover */
56
+ .language-selector__popover {
57
+ --tw-bg-opacity: 1;
58
+ background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
59
+ padding: var(--spacing-padding-px-2);
60
+ border-radius: var(--border-radius-rounded-xl);
61
+ min-width: 8rem;
62
+ }
63
+
64
+ /* Popover Content */
65
+ .language-selector__content {
66
+ display: flex;
67
+ flex-direction: column;
68
+ --tw-bg-opacity: 1;
69
+ background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
70
+ padding-top: 0.25rem;
71
+ padding-bottom: 0.25rem;
72
+ min-width: 8rem;
73
+ }
74
+
75
+ .language-selector__option {
76
+ display: flex;
77
+ width: 100%;
78
+ cursor: pointer;
79
+ align-items: center;
80
+ column-gap: 0.5rem;
81
+ height: 2.25rem;
82
+ padding-inline: var(--spacing-padding-px-3);
83
+ border-radius: var(--border-radius-rounded-md);
84
+ font-size: var(--typography-font-size-sm);
85
+ font-weight: var(--typography-font-weight-medium);
86
+ color: var(--color-neutral-800);
87
+ transition: background-color 0.2s ease;
88
+ }
89
+
90
+ .language-selector__option:hover {
91
+ background-color: var(--color-neutral-100);
92
+ }
93
+
94
+ .language-selector__option--selected {
95
+ background-color: var(--color-neutral-100);
96
+ }
97
+
98
+ .language-selector__selected-language {
99
+ display: flex;
100
+ align-items: center;
101
+ column-gap: 0.5rem;
102
+ }
103
+
104
+ .language-selector__flag {
105
+ display: flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ height: 1rem;
109
+ flex-shrink: 0;
110
+ flex-grow: 0;
111
+ flex-basis: 1rem;
112
+ overflow: hidden;
113
+ border-radius: 9999px;
114
+ .fi {
115
+ width: 1rem;
116
+ }
117
+ .fi {
118
+ flex: 0 0 1.333333em;
119
+ }
120
+ }
@@ -0,0 +1,11 @@
1
+ import 'flag-icons/css/flag-icons.min.css';
2
+ import './LanguageSelector.css';
3
+ export declare const defaultLanguages: string[];
4
+ export interface LanguageSelectorProps {
5
+ languages?: string[];
6
+ defaultLanguage?: string;
7
+ placeholder?: string;
8
+ onSelectLanguage?: (language: string) => void;
9
+ label?: string;
10
+ }
11
+ export default function LanguageSelector(props: LanguageSelectorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../../lib/utils';
3
+ import 'flag-icons/css/flag-icons.min.css';
4
+ import { useEffect, useState } from 'react';
5
+ import Icon from '../../atoms/Icon/Icon';
6
+ import { Text } from '../../atoms/Typography/Typography';
7
+ import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover';
8
+ import { languagesMap } from '../ServiceLanguages/constant';
9
+ import './LanguageSelector.css';
10
+ export var defaultLanguages = ['English', 'Français', 'German', 'Italian'];
11
+ export default function LanguageSelector(props) {
12
+ var _a = props.languages, languages = _a === void 0 ? defaultLanguages : _a, defaultLanguage = props.defaultLanguage, _b = props.placeholder, placeholder = _b === void 0 ? 'Prefered language' : _b, label = props.label, onSelectLanguage = props.onSelectLanguage;
13
+ var _c = useState(false), open = _c[0], setOpen = _c[1];
14
+ var _d = useState(defaultLanguage), selectedLanguage = _d[0], setSelectedLanguage = _d[1];
15
+ var handleSelectLanguage = function (language) {
16
+ setSelectedLanguage(language);
17
+ onSelectLanguage === null || onSelectLanguage === void 0 ? void 0 : onSelectLanguage(language);
18
+ setOpen(false);
19
+ };
20
+ useEffect(function () {
21
+ setSelectedLanguage(defaultLanguage);
22
+ }, [defaultLanguage]);
23
+ return (_jsxs("div", { children: [label && (_jsx("label", { className: "mb-2", children: _jsx(Text, { size: "sm", as: "span", children: label }) })), _jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn('language-selector__trigger', {
24
+ 'language-selector__trigger--with-text': !!selectedLanguage,
25
+ }), children: [selectedLanguage ? (_jsxs("span", { className: "language-selector__selected-language", children: [_jsx("span", { className: "language-selector__flag", children: _jsx("i", { className: "fi fi-".concat(languagesMap[selectedLanguage.toLowerCase()]) }) }), selectedLanguage] })) : (_jsx("span", { className: "language-selector__placeholder", children: placeholder })), _jsx(Icon, { name: "chevron-down", size: "sm", className: "language-selector__trigger-chevron" })] }) }), _jsx(PopoverContent, { className: "language-selector__popover", align: "end", side: "bottom", sideOffset: 8, children: _jsx("div", { className: "language-selector__content", children: languages.map(function (language) { return (_jsxs("div", { className: cn('language-selector__option', {
26
+ 'language-selector__option--selected': selectedLanguage === language,
27
+ }), onClick: function () { return handleSelectLanguage(language); }, children: [_jsx("span", { className: "language-selector__flag", children: _jsx("i", { className: "fi fi-".concat(languagesMap[language.toLowerCase()]) }) }), language] }, language)); }) }) })] })] }));
28
+ }
@@ -15,6 +15,6 @@ import { Text, } from '../../atoms/Typography/Typography';
15
15
  */
16
16
  function TextWithIcon(props) {
17
17
  var icon = props.icon, children = props.children, _a = props.iconSize, iconSize = _a === void 0 ? 'sm' : _a, _b = props.textSize, textSize = _b === void 0 ? 'sm' : _b, _c = props.color, color = _c === void 0 ? 'default' : _c, _d = props.textLeading, textLeading = _d === void 0 ? '5' : _d, _e = props.textVariant, textVariant = _e === void 0 ? 'medium' : _e;
18
- return (_jsxs("div", { className: cn('flex gap-x-2', color === 'yellow' && 'text-[var(--color-yellow-600)]', color === 'accent' && 'text-[var(--color-text-accent)]'), children: [icon && (_jsx("span", { className: "relative top-[2px]", children: _jsx(Icon, { name: icon, size: iconSize }) })), _jsx(Text, { variant: textVariant, size: textSize, className: "flex items-center gap-x-2", color: color, leading: textLeading, as: "div", children: children })] }));
18
+ return (_jsxs("div", { className: cn('flex gap-x-2 items-center', color === 'yellow' && 'text-[var(--color-yellow-600)]', color === 'accent' && 'text-[var(--color-text-accent)]'), children: [icon && (_jsx("span", { className: "relative top-[2px]", children: _jsx(Icon, { name: icon, size: iconSize }) })), _jsx(Text, { variant: textVariant, size: textSize, className: "flex items-center gap-x-2", color: color, leading: textLeading, as: "div", children: children })] }));
19
19
  }
20
20
  export default TextWithIcon;
@@ -3,14 +3,23 @@ import React from 'react';
3
3
  import '../../../styles/components/organism/docket.css';
4
4
  import { DocketService } from '../../../types/docket/services.types';
5
5
  import { ActionDropdownItem } from '../../molecules/ActionDropdown/ActionDropdown';
6
+ import { DocketFooterLabelsType } from './DocketFooter';
6
7
  export { DocketCollapsedHeader } from './DocketCollapsedHeader';
7
8
  export type { DocketCollapsedHeaderProps } from './DocketCollapsedHeader';
8
9
  export { DocketEmptyState } from './DocketEmptyState';
9
- export type { DocketEmptyStateProps } from './DocketEmptyState';
10
+ export type { DocketEmptyStateLabelsType, DocketEmptyStateProps, } from './DocketEmptyState';
10
11
  export { DocketFooter } from './DocketFooter';
11
12
  export type { DocketFooterProps } from './DocketFooter';
12
13
  export { DocketHeader } from './DocketHeader';
13
14
  export type { DocketHeaderProps } from './DocketHeader';
15
+ export type DocketLabelsType = {
16
+ manageQuotation: string;
17
+ close: string;
18
+ /** Bold part of the empty state message */
19
+ emptyStateBold?: string;
20
+ /** Regular part of the empty state message */
21
+ emptyStateRegular?: string;
22
+ } & DocketFooterLabelsType;
14
23
  export interface DocketProps {
15
24
  /**
16
25
  * Array of nested Docket objects
@@ -89,10 +98,6 @@ export interface DocketProps {
89
98
  * Optional click handler
90
99
  */
91
100
  onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
92
- /**
93
- * Optional data attributes for testing or tracking
94
- */
95
- 'data-testid'?: string;
96
101
  /**
97
102
  * Remove mode - replaces price chips with remove buttons in all service dockets
98
103
  */
@@ -102,11 +107,31 @@ export interface DocketProps {
102
107
  * Receives the service index and service data
103
108
  */
104
109
  onServiceRemove?: (index: number, service: DocketService) => void;
110
+ /**
111
+ * Button done mode - replaces the "Book now" button with a "Done" button
112
+ */
113
+ doneButtonMode?: boolean;
114
+ /**
115
+ * Handler for the "Done" button click
116
+ */
117
+ onDoneClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
118
+ /**
119
+ * Labels for the docket
120
+ */
121
+ labels?: DocketLabelsType;
122
+ /**
123
+ * Maximum number of proposals
124
+ */
125
+ maxProposals?: number;
126
+ /**
127
+ * URL of the empty state illustration image (when there are no proposals or no services)
128
+ */
129
+ emptyStateImageUrl?: string;
105
130
  }
106
131
  /**
107
132
  * Docket is a container component for displaying quotation/docket information.
108
133
  * It provides a structured layout for travel booking summaries with sections
109
134
  * for accommodation, services, pricing, and actions.
110
135
  */
111
- export declare const Docket: React.FC<DocketProps>;
136
+ export declare function Docket({ proposals, activeProposal: initialActiveProposal, onProposalSelect, title, moreOptions, accordionMoreOptions, onMoreOptionsClick, onAddNewQuoteClick, onCompareClick, onViewClick, onSaveClick, onBookNowClick, className, containerClassName, onClick, removeMode, onServiceRemove, doneButtonMode, onDoneClick, maxProposals, emptyStateImageUrl, labels, }: DocketProps): React.ReactElement;
112
137
  export default Docket;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
+ import { Breakpoint } from '../../../hooks/useMobile';
3
4
  import '../../../styles/components/organism/docket.css';
4
5
  import Icon from '../../atoms/Icon/Icon';
5
6
  import { AccomodationDocket } from '../../molecules/AccomodationDocket/AccomodationDocket';
@@ -22,14 +23,25 @@ export { DocketHeader } from './DocketHeader';
22
23
  * It provides a structured layout for travel booking summaries with sections
23
24
  * for accommodation, services, pricing, and actions.
24
25
  */
25
- export var Docket = function (_a) {
26
- var proposals = _a.proposals, _b = _a.activeProposal, initialActiveProposal = _b === void 0 ? 0 : _b, onProposalSelect = _a.onProposalSelect, _c = _a.title, title = _c === void 0 ? 'Your quotation' : _c, moreOptions = _a.moreOptions, accordionMoreOptions = _a.accordionMoreOptions, onMoreOptionsClick = _a.onMoreOptionsClick, onAddNewQuoteClick = _a.onAddNewQuoteClick, onCompareClick = _a.onCompareClick, onViewClick = _a.onViewClick, onSaveClick = _a.onSaveClick, onBookNowClick = _a.onBookNowClick, _d = _a.className, className = _d === void 0 ? '' : _d, _e = _a.containerClassName, containerClassName = _e === void 0 ? '' : _e, onClick = _a.onClick, testId = _a["data-testid"], _f = _a.removeMode, removeMode = _f === void 0 ? false : _f, onServiceRemove = _a.onServiceRemove;
27
- var _g = useState(false), isOpen = _g[0], setIsOpen = _g[1];
28
- var _h = useState(false), isMobile = _h[0], setIsMobile = _h[1];
29
- var _j = useState(initialActiveProposal), expandedProposalIndex = _j[0], setExpandedProposalIndex = _j[1];
26
+ export function Docket(_a) {
27
+ var proposals = _a.proposals, _b = _a.activeProposal, initialActiveProposal = _b === void 0 ? 0 : _b, onProposalSelect = _a.onProposalSelect, _c = _a.title, title = _c === void 0 ? 'Your quotation' : _c, moreOptions = _a.moreOptions, accordionMoreOptions = _a.accordionMoreOptions, onMoreOptionsClick = _a.onMoreOptionsClick, onAddNewQuoteClick = _a.onAddNewQuoteClick, onCompareClick = _a.onCompareClick, onViewClick = _a.onViewClick, onSaveClick = _a.onSaveClick, onBookNowClick = _a.onBookNowClick, _d = _a.className, className = _d === void 0 ? '' : _d, _e = _a.containerClassName, containerClassName = _e === void 0 ? '' : _e, onClick = _a.onClick, _f = _a.removeMode, removeMode = _f === void 0 ? false : _f, onServiceRemove = _a.onServiceRemove, _g = _a.doneButtonMode, doneButtonMode = _g === void 0 ? false : _g, onDoneClick = _a.onDoneClick, _h = _a.maxProposals, maxProposals = _h === void 0 ? 5 : _h, emptyStateImageUrl = _a.emptyStateImageUrl, _j = _a.labels, labels = _j === void 0 ? {
28
+ manageQuotation: 'Manage quotation',
29
+ close: 'Close',
30
+ addNewQuote: 'Add new quote',
31
+ compare: 'Compare',
32
+ view: 'View',
33
+ save: 'Save',
34
+ bookNow: 'Book now',
35
+ done: 'Done',
36
+ emptyStateBold: 'Start by adding a service here—',
37
+ emptyStateRegular: "you'll be able to create and compare multiple quotations.",
38
+ } : _j;
39
+ var _k = useState(false), isOpen = _k[0], setIsOpen = _k[1];
40
+ var _l = useState(false), isMobile = _l[0], setIsMobile = _l[1];
41
+ var _m = useState(initialActiveProposal), expandedProposalIndex = _m[0], setExpandedProposalIndex = _m[1];
30
42
  useEffect(function () {
31
43
  var checkMobile = function () {
32
- setIsMobile(window.innerWidth < 1024); // Tablet and mobile breakpoint
44
+ setIsMobile(window.innerWidth < Breakpoint.LG); // Desktop S breakpoint (1440px)
33
45
  };
34
46
  checkMobile();
35
47
  window.addEventListener('resize', checkMobile);
@@ -80,32 +92,40 @@ export var Docket = function (_a) {
80
92
  };
81
93
  var renderContent = function () {
82
94
  if (!proposals || proposals.length === 0) {
83
- return _jsx(DocketEmptyState, {});
95
+ return (_jsx(DocketEmptyState, { imageUrl: emptyStateImageUrl, labels: (labels === null || labels === void 0 ? void 0 : labels.emptyStateBold) != null && (labels === null || labels === void 0 ? void 0 : labels.emptyStateRegular) != null
96
+ ? { bold: labels.emptyStateBold, regular: labels.emptyStateRegular }
97
+ : undefined }));
84
98
  }
85
99
  // If there are multiple proposals, render each in a DocketAccordion
86
100
  if (proposals.length > 1) {
87
- return (_jsx("div", { className: "docket__proposals", children: proposals.map(function (proposal, index) { return (_jsx(DocketAccordion, { proposal: proposal, removeMode: removeMode && index === expandedProposalIndex, onServiceRemove: onServiceRemove, expanded: index === expandedProposalIndex, onExpandedChange: function (isExpanded) { return handleProposalToggle(index, isExpanded); }, moreOptions: accordionMoreOptions }, "proposal-".concat(proposal.ProposalDetail.QuoteId))); }) }));
101
+ return (_jsx("div", { className: "docket__proposals", children: proposals.map(function (proposal, index) { return (_jsx(DocketAccordion, { proposal: proposal, removeMode: removeMode && index === expandedProposalIndex, onServiceRemove: onServiceRemove, expanded: index === expandedProposalIndex, onExpandedChange: function (isExpanded) { return handleProposalToggle(index, isExpanded); }, moreOptions: accordionMoreOptions, manageQuotationLabel: labels === null || labels === void 0 ? void 0 : labels.manageQuotation, emptyStateImageUrl: emptyStateImageUrl, emptyStateLabels: (labels === null || labels === void 0 ? void 0 : labels.emptyStateBold) != null && (labels === null || labels === void 0 ? void 0 : labels.emptyStateRegular) != null
102
+ ? { bold: labels.emptyStateBold, regular: labels.emptyStateRegular }
103
+ : undefined }, "proposal-".concat(proposal.ProposalDetail.QuoteId))); }) }));
88
104
  }
89
105
  // If there's only one proposal, render services directly
90
106
  var currentProposal = proposals[0];
91
107
  var allServices = currentProposal.Services || [];
92
108
  if (allServices.length === 0) {
93
- return _jsx(DocketEmptyState, {});
109
+ return (_jsx(DocketEmptyState, { imageUrl: emptyStateImageUrl, labels: (labels === null || labels === void 0 ? void 0 : labels.emptyStateBold) != null && (labels === null || labels === void 0 ? void 0 : labels.emptyStateRegular) != null
110
+ ? { bold: labels.emptyStateBold, regular: labels.emptyStateRegular }
111
+ : undefined }));
94
112
  }
95
113
  var renderedServices = allServices
96
114
  .map(function (service, index) { return renderService(service, index); })
97
115
  .filter(Boolean);
98
116
  if (renderedServices.length === 0) {
99
- return _jsx(DocketEmptyState, {});
117
+ return (_jsx(DocketEmptyState, { imageUrl: emptyStateImageUrl, labels: (labels === null || labels === void 0 ? void 0 : labels.emptyStateBold) != null && (labels === null || labels === void 0 ? void 0 : labels.emptyStateRegular) != null
118
+ ? { bold: labels.emptyStateBold, regular: labels.emptyStateRegular }
119
+ : undefined }));
100
120
  }
101
121
  return _jsx("div", { className: "docket__services", children: renderedServices });
102
122
  };
103
123
  // Collect all prices from the current proposal (only for single proposal view)
104
124
  var allPrices = proposals && proposals.length === 1 ? proposals[0].Prices || [] : [];
105
- var renderDocketContent = function () { return (_jsxs("div", { className: classes, onClick: onClick, "data-testid": testId, children: [_jsx(DocketHeader, { title: title, moreOptions: moreOptions, onMoreOptionsClick: onMoreOptionsClick }), _jsx("div", { className: "docket__content", children: renderContent() }), allPrices.length > 0 && proposals && proposals.length === 1 && (_jsxs("div", { className: "docket__prices-section", children: [_jsx(Icon, { name: "line", size: "lg" }), _jsx(DocketPrices, { prices: allPrices }), _jsx(Icon, { name: "line", size: "lg" })] })), _jsx(DocketFooter, { onAddNewQuoteClick: onAddNewQuoteClick, onCompareClick: onCompareClick, showCompareButton: !!(proposals === null || proposals === void 0 ? void 0 : proposals.length), onViewClick: onViewClick, onSaveClick: onSaveClick, onBookNowClick: onBookNowClick })] })); };
125
+ var renderDocketContent = function () { return (_jsxs("div", { className: classes, onClick: onClick, children: [_jsx(DocketHeader, { title: title, moreOptions: moreOptions, onMoreOptionsClick: onMoreOptionsClick }), _jsx("div", { className: "docket__content", children: renderContent() }), allPrices.length > 0 && proposals && proposals.length === 1 && (_jsxs("div", { className: "docket__prices-section", children: [_jsx(Icon, { name: "line", size: "lg" }), _jsx(DocketPrices, { prices: allPrices }), _jsx(Icon, { name: "line", size: "lg" })] })), _jsx(DocketFooter, { onAddNewQuoteClick: onAddNewQuoteClick, onCompareClick: onCompareClick, showCompareButton: !!(proposals === null || proposals === void 0 ? void 0 : proposals.length), onViewClick: onViewClick, onSaveClick: onSaveClick, onBookNowClick: onBookNowClick, doneButtonMode: doneButtonMode, onDoneClick: onDoneClick, labels: labels, disableAddNewQuoteButton: proposals ? proposals.length >= maxProposals : false })] })); };
106
126
  var containerClasses = containerClassName
107
127
  ? "docket__container ".concat(containerClassName)
108
128
  : 'docket__container';
109
- return (_jsxs("div", { className: containerClasses, children: [isMobile && !isOpen && (_jsx(DocketCollapsedHeader, { title: title, onClick: handleToggle })), isMobile && isOpen && (_jsxs("div", { className: "docket__mobile-wrapper", children: [_jsx("div", { className: "docket__close-header", children: _jsxs("div", { className: "docket__close-header-content", children: [_jsx("h2", { className: "docket__close-header-text", children: "Close" }), _jsx("button", { className: "docket__close-button", onClick: handleClose, "aria-label": "Close docket", children: _jsx(Icon, { name: "close", size: "lg" }) })] }) }), renderDocketContent()] })), !isMobile && renderDocketContent()] }));
110
- };
129
+ return (_jsxs("div", { className: containerClasses, children: [isMobile && !isOpen && (_jsx(DocketCollapsedHeader, { title: title, onClick: handleToggle })), isMobile && isOpen && (_jsxs("div", { className: "docket__mobile-wrapper", children: [_jsx("button", { className: "docket__close-header", onClick: handleClose, children: _jsxs("div", { className: "docket__close-header-content", children: [_jsx("h2", { className: "docket__close-header-text", children: labels === null || labels === void 0 ? void 0 : labels.close }), _jsx("div", { className: "docket__close-button", "aria-label": "Close docket", children: _jsx(Icon, { name: "close", size: "lg" }) })] }) }), renderDocketContent()] })), !isMobile && renderDocketContent()] }));
130
+ }
111
131
  export default Docket;
@@ -1,12 +1,23 @@
1
1
  import React from 'react';
2
+ export type DocketEmptyStateLabelsType = {
3
+ /** Bold part of the empty state message */
4
+ bold: string;
5
+ /** Regular part of the empty state message */
6
+ regular: string;
7
+ };
2
8
  export interface DocketEmptyStateProps {
9
+ /**
10
+ * URL of the empty state illustration image
11
+ */
12
+ imageUrl?: string;
13
+ /**
14
+ * Labels for the empty state text (bold and regular parts)
15
+ */
16
+ labels?: DocketEmptyStateLabelsType;
3
17
  /**
4
18
  * Additional CSS classes
5
19
  */
6
20
  className?: string;
7
21
  }
8
- /**
9
- * Empty state component for docket when no content is provided
10
- */
11
22
  export declare const DocketEmptyState: React.FC<DocketEmptyStateProps>;
12
23
  export default DocketEmptyState;
@@ -2,8 +2,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * Empty state component for docket when no content is provided
4
4
  */
5
+ var DEFAULT_EMPTY_STATE_IMAGE = '/images/docket-empty-illustration.svg';
6
+ var DEFAULT_EMPTY_STATE_LABELS = {
7
+ bold: 'Start by adding a service here—',
8
+ regular: "you'll be able to create and compare multiple quotations.",
9
+ };
5
10
  export var DocketEmptyState = function (_a) {
6
- var _b = _a.className, className = _b === void 0 ? '' : _b;
7
- return (_jsx("div", { className: "docket__empty-state ".concat(className), children: _jsxs("div", { className: "docket__empty-state-content", children: [_jsx("div", { className: "docket__empty-state-illustration", children: _jsx("img", { src: "/images/docket-empty-illustration.svg", alt: "Empty docket illustration", className: "docket__empty-state-image" }) }), _jsxs("p", { className: "docket__empty-state-text", children: [_jsx("span", { className: "docket__empty-state-text-bold", children: "Start by adding a service here\u2014" }), _jsx("span", { className: "docket__empty-state-text-regular", children: "you'll be able to create and compare multiple quotations." })] })] }) }));
11
+ var _b = _a.imageUrl, imageUrl = _b === void 0 ? DEFAULT_EMPTY_STATE_IMAGE : _b, _c = _a.labels, labels = _c === void 0 ? DEFAULT_EMPTY_STATE_LABELS : _c, _d = _a.className, className = _d === void 0 ? '' : _d;
12
+ return (_jsx("div", { className: "docket__empty-state ".concat(className), children: _jsxs("div", { className: "docket__empty-state-content", children: [_jsx("div", { className: "docket__empty-state-illustration", children: _jsx("img", { src: imageUrl, alt: "Empty docket illustration", className: "docket__empty-state-image" }) }), _jsxs("p", { className: "docket__empty-state-text", children: [_jsx("span", { className: "docket__empty-state-text-bold", children: labels.bold }), _jsx("span", { className: "docket__empty-state-text-regular", children: labels.regular })] })] }) }));
8
13
  };
9
14
  export default DocketEmptyState;
@@ -1,4 +1,12 @@
1
1
  import React from 'react';
2
+ export type DocketFooterLabelsType = {
3
+ addNewQuote: string;
4
+ compare: string;
5
+ view: string;
6
+ save: string;
7
+ bookNow: string;
8
+ done: string;
9
+ };
2
10
  export interface DocketFooterProps {
3
11
  /**
4
12
  * Handler for "Add new quote" button click
@@ -28,6 +36,22 @@ export interface DocketFooterProps {
28
36
  * Additional CSS classes
29
37
  */
30
38
  className?: string;
39
+ /**
40
+ * Button done mode - replaces the "Book now" button with a "Done" button
41
+ */
42
+ doneButtonMode?: boolean;
43
+ /**
44
+ * Handler for the "Done" button click
45
+ */
46
+ onDoneClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
47
+ /**
48
+ * Disable the "Add new quote" button
49
+ */
50
+ disableAddNewQuoteButton?: boolean;
51
+ /**
52
+ * Labels for the buttons
53
+ */
54
+ labels?: DocketFooterLabelsType;
31
55
  }
32
56
  /**
33
57
  * DocketFooter component for action buttons
@@ -1,10 +1,18 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import Button from '../../atoms/Button/Button';
3
3
  /**
4
4
  * DocketFooter component for action buttons
5
5
  */
6
6
  export var DocketFooter = function (_a) {
7
- var onAddNewQuoteClick = _a.onAddNewQuoteClick, onCompareClick = _a.onCompareClick, _b = _a.showCompareButton, showCompareButton = _b === void 0 ? false : _b, onViewClick = _a.onViewClick, onSaveClick = _a.onSaveClick, onBookNowClick = _a.onBookNowClick, _c = _a.className, className = _c === void 0 ? '' : _c;
8
- return (_jsxs("div", { className: "docket__footer ".concat(className), children: [(onAddNewQuoteClick || onCompareClick) && (_jsxs("div", { className: "docket__footer-top-buttons", children: [onAddNewQuoteClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", leadingIcon: "plus", onClick: onAddNewQuoteClick, className: "docket__footer-button ".concat(!showCompareButton ? 'docket__footer-button--full' : ''), children: "Add new quote" })), showCompareButton && onCompareClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", onClick: onCompareClick, leadingIcon: "document", className: "docket__footer-button", children: "Compare" }))] })), _jsxs("div", { className: "docket__footer-actions", children: [onViewClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", onClick: onViewClick, className: "docket__footer-view-link", children: _jsx("span", { className: "docket__footer-view-text", children: "View" }) })), onSaveClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", onClick: onSaveClick, className: "docket__footer-button", children: "Save" })), onBookNowClick && (_jsx(Button, { variant: "secondary", size: "sm", onClick: onBookNowClick, className: "docket__footer-button docket__footer-button--primary", children: "Book now" }))] })] }));
7
+ var onAddNewQuoteClick = _a.onAddNewQuoteClick, onCompareClick = _a.onCompareClick, _b = _a.showCompareButton, showCompareButton = _b === void 0 ? false : _b, onViewClick = _a.onViewClick, onSaveClick = _a.onSaveClick, onBookNowClick = _a.onBookNowClick, _c = _a.className, className = _c === void 0 ? '' : _c, _d = _a.doneButtonMode, doneButtonMode = _d === void 0 ? false : _d, onDoneClick = _a.onDoneClick, _e = _a.disableAddNewQuoteButton, disableAddNewQuoteButton = _e === void 0 ? false : _e, _f = _a.labels, labels = _f === void 0 ? {
8
+ addNewQuote: 'Add new quote',
9
+ compare: 'Compare',
10
+ view: 'View',
11
+ save: 'Save',
12
+ bookNow: 'Book now',
13
+ done: 'Done',
14
+ } : _f;
15
+ var isDoneMode = doneButtonMode && onDoneClick;
16
+ return (_jsxs("div", { className: "docket__footer ".concat(className), children: [!isDoneMode && (onAddNewQuoteClick || onCompareClick) && (_jsxs("div", { className: "docket__footer-top-buttons", children: [onAddNewQuoteClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", leadingIcon: disableAddNewQuoteButton ? undefined : 'plus', trailingIcon: disableAddNewQuoteButton ? 'info' : undefined, disabled: disableAddNewQuoteButton, onClick: onAddNewQuoteClick, className: "docket__footer-button ".concat(!showCompareButton ? 'docket__footer-button--full' : ''), children: labels.addNewQuote })), showCompareButton && onCompareClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", onClick: onCompareClick, leadingIcon: "document", className: "docket__footer-button", children: labels.compare }))] })), _jsx("div", { className: "docket__footer-actions", children: isDoneMode ? (_jsx(Button, { variant: "secondary", size: "sm", onClick: onDoneClick, className: "docket__footer-button docket__footer-button--primary docket__footer-button--half", children: labels.done })) : (_jsxs(_Fragment, { children: [onViewClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", onClick: onViewClick, className: "docket__footer-button", children: _jsx("span", { className: "docket__footer-view-text", children: labels.view }) })), onSaveClick && (_jsx(Button, { variant: "outline-secondary", size: "sm", onClick: onSaveClick, className: "docket__footer-button", children: labels.save })), onBookNowClick && (_jsx(Button, { variant: "secondary", size: "sm", onClick: onBookNowClick, className: "docket__footer-button docket__footer-button--primary", children: labels.bookNow }))] })) })] }));
9
17
  };
10
18
  export default DocketFooter;
@@ -1,6 +1,7 @@
1
1
  import { ProposalSorted } from '@/src/types/docket/docket.types';
2
2
  import { DocketService } from '@/src/types/docket/services.types';
3
3
  import { ActionDropdownItem } from '../../molecules/ActionDropdown/ActionDropdown';
4
+ import { type DocketEmptyStateLabelsType } from '../Docket/Docket';
4
5
  export interface DocketAccordionProps {
5
6
  proposal: ProposalSorted;
6
7
  removeMode?: boolean;
@@ -10,6 +11,14 @@ export interface DocketAccordionProps {
10
11
  expanded?: boolean;
11
12
  onExpandedChange?: (expanded: boolean) => void;
12
13
  moreOptions?: ActionDropdownItem[];
14
+ /**
15
+ * URL of the empty state illustration image (when the proposal has no services)
16
+ */
17
+ emptyStateImageUrl?: string;
18
+ /**
19
+ * Labels for the empty state (bold and regular text) when the proposal has no services
20
+ */
21
+ emptyStateLabels?: DocketEmptyStateLabelsType;
13
22
  }
14
23
  /**
15
24
  * DocketAccordion component displays a single quotation in an accordion format.
@@ -23,4 +32,4 @@ export interface DocketAccordionProps {
23
32
  * defaultExpanded={false}
24
33
  * />
25
34
  */
26
- export default function DocketAccordion({ proposal, removeMode, onServiceRemove, defaultExpanded, expanded, onExpandedChange, moreOptions, manageQuotationLabel, }: DocketAccordionProps): import("react/jsx-runtime").JSX.Element;
35
+ export default function DocketAccordion({ proposal, removeMode, onServiceRemove, defaultExpanded, expanded, onExpandedChange, moreOptions, manageQuotationLabel, emptyStateImageUrl, emptyStateLabels, }: DocketAccordionProps): import("react/jsx-runtime").JSX.Element;
@@ -22,7 +22,7 @@ import { DocketEmptyState } from '../Docket/Docket';
22
22
  * />
23
23
  */
24
24
  export default function DocketAccordion(_a) {
25
- var proposal = _a.proposal, _b = _a.removeMode, removeMode = _b === void 0 ? false : _b, onServiceRemove = _a.onServiceRemove, _c = _a.defaultExpanded, defaultExpanded = _c === void 0 ? false : _c, expanded = _a.expanded, onExpandedChange = _a.onExpandedChange, _d = _a.moreOptions, moreOptions = _d === void 0 ? [] : _d, _e = _a.manageQuotationLabel, manageQuotationLabel = _e === void 0 ? 'Manage quotation' : _e;
25
+ var proposal = _a.proposal, _b = _a.removeMode, removeMode = _b === void 0 ? false : _b, onServiceRemove = _a.onServiceRemove, _c = _a.defaultExpanded, defaultExpanded = _c === void 0 ? false : _c, expanded = _a.expanded, onExpandedChange = _a.onExpandedChange, _d = _a.moreOptions, moreOptions = _d === void 0 ? [] : _d, _e = _a.manageQuotationLabel, manageQuotationLabel = _e === void 0 ? 'Manage quotation' : _e, emptyStateImageUrl = _a.emptyStateImageUrl, emptyStateLabels = _a.emptyStateLabels;
26
26
  var allServices = proposal.Services || [];
27
27
  var renderAccordionTitle = function (isExpanded) {
28
28
  var _a;
@@ -52,5 +52,5 @@ export default function DocketAccordion(_a) {
52
52
  transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
53
53
  transition: 'transform 0.2s ease-in-out',
54
54
  } })] })); } }), _jsx(Icon, { name: "line", size: "md" }), _jsx(DocketPrices, { prices: proposal.Prices, className: "docket-accordion__footer-price-list" })] }));
55
- return (_jsx(Accordion, { title: proposal.ProposalDetail.Label, renderTitle: renderAccordionTitle, classNameExpanded: "docket-accordion__expanded", defaultExpanded: defaultExpanded, expanded: expanded, onExpandedChange: onExpandedChange, footer: (allServices === null || allServices === void 0 ? void 0 : allServices.length) > 0 ? renderAccordionFooter : undefined, children: _jsx("div", { className: "docket-accordion__content", children: allServices.length === 0 ? (_jsx(DocketEmptyState, {})) : (_jsx("div", { className: "docket-accordion__services", children: allServices.map(function (service, index) { return renderService(service, index); }) })) }) }));
55
+ return (_jsx(Accordion, { title: proposal.ProposalDetail.Label, renderTitle: renderAccordionTitle, classNameExpanded: "docket-accordion__expanded", defaultExpanded: defaultExpanded, expanded: expanded, onExpandedChange: onExpandedChange, footer: (allServices === null || allServices === void 0 ? void 0 : allServices.length) > 0 ? renderAccordionFooter : undefined, children: _jsx("div", { className: "docket-accordion__content", children: allServices.length === 0 ? (_jsx(DocketEmptyState, { imageUrl: emptyStateImageUrl, labels: emptyStateLabels })) : (_jsx("div", { className: "docket-accordion__services", children: allServices.map(function (service, index) { return renderService(service, index); }) })) }) }));
56
56
  }
@@ -1,7 +1,8 @@
1
1
  export declare enum Breakpoint {
2
2
  SM = 768,
3
3
  MD = 1024,
4
- LG = 1280
4
+ LG = 1280,
5
+ XL = 1440
5
6
  }
6
7
  export declare function useMobile(breakpoint?: Breakpoint): {
7
8
  isMobile: boolean;
@@ -4,6 +4,7 @@ export var Breakpoint;
4
4
  Breakpoint[Breakpoint["SM"] = 768] = "SM";
5
5
  Breakpoint[Breakpoint["MD"] = 1024] = "MD";
6
6
  Breakpoint[Breakpoint["LG"] = 1280] = "LG";
7
+ Breakpoint[Breakpoint["XL"] = 1440] = "XL";
7
8
  })(Breakpoint || (Breakpoint = {}));
8
9
  export function useMobile(breakpoint) {
9
10
  if (breakpoint === void 0) { breakpoint = Breakpoint.SM; }
@@ -252,24 +252,6 @@
252
252
  width: 100%;
253
253
  }
254
254
 
255
- .docket__footer-view-link {
256
- display: inline-flex;
257
- align-items: center;
258
- gap: var(--component-button-spacing-ghost-sm-gap, 6px);
259
- background: none;
260
- border: none;
261
- padding: var(--component-button-spacing-ghost-sm-padding-y, 0px)
262
- var(--component-button-spacing-ghost-sm-padding-x, 0px);
263
- cursor: pointer;
264
- font-family: var(--font-font-family-body, 'Satoshi', sans-serif);
265
- font-size: var(--font-size-text-sm, 14px);
266
- font-weight: var(--font-weight-font-medium, 500);
267
- line-height: var(--font-leading-leading-sm, 20px);
268
- color: var(--color-button-ghost-foreground-default, #78716c);
269
- text-decoration: none;
270
- transition: color 0.2s ease;
271
- }
272
-
273
255
  .docket__footer-view-text {
274
256
  display: inline-block;
275
257
  }
@@ -300,6 +282,16 @@
300
282
  flex: 2;
301
283
  }
302
284
 
285
+ .docket__footer-actions .docket__footer-button--half {
286
+ flex: 0 0 50%;
287
+ max-width: 50%;
288
+ }
289
+
290
+ .docket__footer-button:disabled {
291
+ border: var(--button-border-width-outline-default, 1px) solid
292
+ var(--button-color-outline-secondary-border-disabled, #a3a3a3) !important;
293
+ }
294
+
303
295
  /* Collapsed header for mobile/tablet */
304
296
 
305
297
  .docket__collapsed-header {
@@ -407,7 +399,7 @@
407
399
 
408
400
  /* Responsive behavior */
409
401
 
410
- @media (max-width: 1023px) {
402
+ @media (max-width: 1439px) {
411
403
  .docket {
412
404
  width: 384px;
413
405
  }
@@ -451,7 +443,9 @@
451
443
  }
452
444
  }
453
445
 
454
- @media (min-width: 1024px) {
446
+ /* Desktop and up */
447
+
448
+ @media (min-width: 1440px) {
455
449
  .docket__collapsed-header,
456
450
  .docket__close-header {
457
451
  display: none;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mautourco-components",
3
- "version": "0.2.142",
3
+ "version": "0.2.144",
4
4
  "private": false,
5
5
  "description": "Bibliothèque de composants Mautourco pour le redesign",
6
6
  "main": "dist/index.js",