@homefile/components-v2 2.59.2 → 2.60.1
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/assets/locales/en/index.json +5 -2
- package/dist/components/folderPanel/displayFiles/GridFile.js +9 -1
- package/dist/components/folderPanel/displayFiles/ListFile.js +9 -1
- package/dist/components/forms/dynamicForm/DynamicForm.js +1 -1
- package/dist/components/forms/dynamicForm/HiddenField.js +2 -2
- package/dist/components/forms/dynamicForm/fields/HomeInitialSetup.js +3 -1
- package/dist/components/forms/readOnly/ReadOnlyDynamicForm.js +21 -3
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyAppliances.js +65 -22
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyGuidelines.js +6 -3
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyHistory.d.ts +2 -0
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyHistory.js +35 -0
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyItemRelated.js +8 -3
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyOverview.d.ts +2 -0
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyOverview.js +16 -0
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyPurchaseDetails.d.ts +2 -0
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyPurchaseDetails.js +30 -0
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyWarrantyBanner.d.ts +2 -0
- package/dist/components/forms/readOnly/fields/homeItem/ReadOnlyWarrantyBanner.js +69 -0
- package/dist/components/forms/readOnly/fields/homeItem/index.d.ts +4 -0
- package/dist/components/forms/readOnly/fields/homeItem/index.js +4 -0
- package/dist/components/headers/TabsHeader.js +1 -1
- package/dist/components/history/AddDocuments.d.ts +7 -0
- package/dist/components/history/AddDocuments.js +8 -0
- package/dist/components/history/DatePennant.d.ts +7 -0
- package/dist/components/history/DatePennant.js +6 -0
- package/dist/components/history/HistoryCard.d.ts +19 -0
- package/dist/components/history/HistoryCard.js +13 -0
- package/dist/components/history/index.d.ts +3 -0
- package/dist/components/history/index.js +3 -0
- package/dist/components/homeBoard/AddToHomefile.js +1 -1
- package/dist/components/homeBoard/HomeCard.js +1 -1
- package/dist/components/homeItems/ViewingHomeItemBody.d.ts +2 -0
- package/dist/components/homeItems/ViewingHomeItemBody.js +41 -0
- package/dist/components/homeItems/ViewingHomeItemPanel.js +17 -19
- package/dist/components/homeItems/index.d.ts +1 -0
- package/dist/components/homeItems/index.js +1 -0
- package/dist/components/homi/HomiPresence.d.ts +2 -0
- package/dist/components/homi/HomiPresence.js +31 -0
- package/dist/components/homi/HomiVoice.d.ts +2 -0
- package/dist/components/homi/HomiVoice.js +6 -0
- package/dist/components/homi/ProgressBar.d.ts +2 -0
- package/dist/components/homi/ProgressBar.js +9 -0
- package/dist/components/homi/RevealValueCard.d.ts +2 -0
- package/dist/components/homi/RevealValueCard.js +23 -0
- package/dist/components/homi/StaggerReveal.d.ts +2 -0
- package/dist/components/homi/StaggerReveal.js +29 -0
- package/dist/components/homi/index.d.ts +5 -0
- package/dist/components/homi/index.js +5 -0
- package/dist/components/inboxTile/InboxForwardBanner.js +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/components/inputs/InlineEditField.d.ts +2 -0
- package/dist/components/inputs/InlineEditField.js +15 -0
- package/dist/components/inputs/RadioCard.d.ts +3 -1
- package/dist/components/inputs/RadioCard.js +3 -3
- package/dist/components/inputs/TextInput.d.ts +1 -1
- package/dist/components/inputs/TextInput.js +11 -4
- package/dist/components/inputs/index.d.ts +1 -0
- package/dist/components/inputs/index.js +1 -0
- package/dist/components/myHomes/HomeDetailsContent.js +1 -1
- package/dist/components/myHomes/IncludePublicRecords.d.ts +13 -1
- package/dist/components/myHomes/IncludePublicRecords.js +16 -6
- package/dist/components/myHomes/edithome/EditHomeDetails.js +12 -3
- package/dist/components/myHomes/steps/NewHomeDetails.d.ts +1 -1
- package/dist/components/myHomes/steps/NewHomeDetails.js +3 -3
- package/dist/components/myProfile/MyProfileBody.d.ts +1 -1
- package/dist/components/myProfile/MyProfileBody.js +2 -2
- package/dist/components/myProfile/details/HomiSms.d.ts +1 -1
- package/dist/components/myProfile/details/HomiSms.js +53 -23
- package/dist/components/myProfile/details/TwoFactorSetting.js +2 -1
- package/dist/components/rooms/RoomHeader.d.ts +1 -1
- package/dist/components/rooms/RoomHeader.js +3 -3
- package/dist/components/wizard/ControlledWizard.d.ts +1 -1
- package/dist/components/wizard/ControlledWizard.js +42 -3
- package/dist/components/wizard/WizardInitialOptions.js +3 -3
- package/dist/components/wizard/WizardSelectCard.d.ts +14 -0
- package/dist/components/wizard/WizardSelectCard.js +32 -0
- package/dist/components/wizard/WizardStepPrompt.d.ts +11 -0
- package/dist/components/wizard/WizardStepPrompt.js +20 -0
- package/dist/components/wizard/WizardSuccessHeader.d.ts +1 -1
- package/dist/components/wizard/WizardSuccessHeader.js +2 -2
- package/dist/components/wizard/index.d.ts +2 -0
- package/dist/components/wizard/index.js +2 -0
- package/dist/helpers/forms/dynamicForm.helper.js +4 -0
- package/dist/hooks/folderPanel/useDisplayFiles.js +11 -2
- package/dist/hooks/forms/useAddressStored.js +8 -2
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/motion/index.d.ts +2 -0
- package/dist/hooks/motion/index.js +2 -0
- package/dist/hooks/motion/useCountUp.d.ts +10 -0
- package/dist/hooks/motion/useCountUp.js +39 -0
- package/dist/hooks/motion/usePrefersReducedMotion.d.ts +14 -0
- package/dist/hooks/motion/usePrefersReducedMotion.js +15 -0
- package/dist/hooks/rooms/useRoomHeader.d.ts +4 -1
- package/dist/hooks/rooms/useRoomHeader.js +9 -1
- package/dist/hooks/useDirtySave.d.ts +14 -0
- package/dist/hooks/useDirtySave.js +33 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/interfaces/forms/dynamicForm/DynamicForm.interface.d.ts +7 -3
- package/dist/interfaces/forms/readOnly/homeItem/ReadOnlyOverview.interface.d.ts +2 -0
- package/dist/interfaces/forms/readOnly/homeItem/ReadOnlyOverview.interface.js +1 -0
- package/dist/interfaces/forms/readOnly/homeItem/ReadOnlyPurchaseDetails.interface.d.ts +5 -0
- package/dist/interfaces/forms/readOnly/homeItem/ReadOnlyPurchaseDetails.interface.js +1 -0
- package/dist/interfaces/forms/readOnly/homeItem/ReadOnlyWarrantyBanner.interface.d.ts +54 -0
- package/dist/interfaces/forms/readOnly/homeItem/ReadOnlyWarrantyBanner.interface.js +1 -0
- package/dist/interfaces/forms/readOnly/homeItem/index.d.ts +3 -0
- package/dist/interfaces/forms/readOnly/homeItem/index.js +3 -0
- package/dist/interfaces/homeItems/ViewingHomeItemPanel.interface.d.ts +1 -0
- package/dist/interfaces/homi/HomiPresence.interface.d.ts +9 -0
- package/dist/interfaces/homi/HomiPresence.interface.js +1 -0
- package/dist/interfaces/homi/ProgressBar.interface.d.ts +8 -0
- package/dist/interfaces/homi/ProgressBar.interface.js +1 -0
- package/dist/interfaces/homi/RevealValueCard.interface.d.ts +16 -0
- package/dist/interfaces/homi/RevealValueCard.interface.js +1 -0
- package/dist/interfaces/homi/StaggerReveal.interface.d.ts +9 -0
- package/dist/interfaces/homi/StaggerReveal.interface.js +1 -0
- package/dist/interfaces/homi/index.d.ts +4 -0
- package/dist/interfaces/homi/index.js +4 -0
- package/dist/interfaces/index.d.ts +1 -0
- package/dist/interfaces/index.js +1 -0
- package/dist/interfaces/inputs/InlineEditField.interface.d.ts +7 -0
- package/dist/interfaces/inputs/InlineEditField.interface.js +1 -0
- package/dist/interfaces/inputs/Input.interface.d.ts +6 -1
- package/dist/interfaces/inputs/index.d.ts +1 -0
- package/dist/interfaces/inputs/index.js +1 -0
- package/dist/interfaces/myHomes/AddHomeContent.interface.d.ts +3 -0
- package/dist/interfaces/myProfile/MyProfileBody.interface.d.ts +1 -0
- package/dist/interfaces/myProfile/details/HomiSms.interface.d.ts +11 -2
- package/dist/interfaces/rooms/RoomHeader.interface.d.ts +5 -0
- package/dist/interfaces/wizard/ControlledWizard.interface.d.ts +6 -0
- package/dist/interfaces/wizard/WizardStepPrompt.interface.d.ts +9 -0
- package/dist/interfaces/wizard/WizardStepPrompt.interface.js +1 -0
- package/dist/interfaces/wizard/index.d.ts +1 -0
- package/dist/interfaces/wizard/index.js +1 -0
- package/dist/stories/forms/readOnly/ReadOnlyAppliances.stories.d.ts +4 -0
- package/dist/stories/forms/readOnly/ReadOnlyAppliances.stories.js +33 -0
- package/dist/stories/forms/readOnly/ReadOnlyWarrantyBanner.stories.d.ts +4 -0
- package/dist/stories/forms/readOnly/ReadOnlyWarrantyBanner.stories.js +10 -0
- package/dist/stories/homeItems/ReadOnlyHistory.stories.d.ts +4 -0
- package/dist/stories/homeItems/ReadOnlyHistory.stories.js +46 -0
- package/dist/stories/homeItems/ReadOnlyOverview.stories.d.ts +5 -0
- package/dist/stories/homeItems/ReadOnlyOverview.stories.js +69 -0
- package/dist/stories/homeItems/ViewingHomeItemPanel.stories.d.ts +4 -0
- package/dist/stories/homeItems/ViewingHomeItemPanel.stories.js +204 -0
- package/dist/stories/homi/HomiPresence.stories.d.ts +18 -0
- package/dist/stories/homi/HomiPresence.stories.js +11 -0
- package/dist/stories/homi/HomiVoice.stories.d.ts +4 -0
- package/dist/stories/homi/HomiVoice.stories.js +8 -0
- package/dist/stories/homi/ProgressBar.stories.d.ts +10 -0
- package/dist/stories/homi/ProgressBar.stories.js +9 -0
- package/dist/stories/homi/RevealValueCard.stories.d.ts +19 -0
- package/dist/stories/homi/RevealValueCard.stories.js +22 -0
- package/dist/stories/homi/StaggerReveal.stories.d.ts +5 -0
- package/dist/stories/homi/StaggerReveal.stories.js +8 -0
- package/dist/stories/inputs/InlineEditField.stories.d.ts +10 -0
- package/dist/stories/inputs/InlineEditField.stories.js +11 -0
- package/dist/stories/myProfile/MyProfilePanel.stories.js +1 -1
- package/dist/stories/myProfile/details/HomiSms.stories.d.ts +3 -2
- package/dist/stories/myProfile/details/HomiSms.stories.js +3 -2
- package/dist/stories/wizard/ControlledWizard.stories.d.ts +9 -0
- package/dist/stories/wizard/ControlledWizard.stories.js +41 -60
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.js +7 -4
- package/dist/utils/Formaters.utils.d.ts +2 -0
- package/dist/utils/Formaters.utils.js +14 -0
- package/dist/utils/Weather.utils.js +11 -4
- package/package.json +1 -1
|
@@ -546,7 +546,7 @@
|
|
|
546
546
|
"title": "You are viewing "
|
|
547
547
|
},
|
|
548
548
|
"details": {
|
|
549
|
-
"header": "
|
|
549
|
+
"header": "Edit Home",
|
|
550
550
|
"tabs": {
|
|
551
551
|
"tab1": "Details",
|
|
552
552
|
"tab2": "Projects",
|
|
@@ -558,6 +558,7 @@
|
|
|
558
558
|
"title": "Let’s add your first home."
|
|
559
559
|
},
|
|
560
560
|
"form": {
|
|
561
|
+
"editHomeName": "Home Name",
|
|
561
562
|
"externalLink": "Add optional external link",
|
|
562
563
|
"homeName": "Name your home",
|
|
563
564
|
"name": "Name or Project Number",
|
|
@@ -626,6 +627,7 @@
|
|
|
626
627
|
"2FactorSubtitle": "Select how you would like to receive your 2FA codes. These codes keep your account secure.",
|
|
627
628
|
"2FactorTitle": "2 Factor Authentication (2FA)",
|
|
628
629
|
"homiSmsAlt": "Homi SMS",
|
|
630
|
+
"homiSmsConsent": "SMS messaging consent & terms",
|
|
629
631
|
"homiSmsSubtitle": "Enable SMS messaging to interact with Homi without a mobile app. Text images, documents, and information directly into Homefile so Homi can capture and organize it for you automatically.",
|
|
630
632
|
"homiSmsTitle": "Enable Homi SMS Messaging"
|
|
631
633
|
},
|
|
@@ -1062,7 +1064,8 @@
|
|
|
1062
1064
|
"title": "Reset your Password"
|
|
1063
1065
|
},
|
|
1064
1066
|
"roomHeader": {
|
|
1065
|
-
"
|
|
1067
|
+
"estValue": "Est. value",
|
|
1068
|
+
"roomValue": "Room value",
|
|
1066
1069
|
"saveBtn": "Save"
|
|
1067
1070
|
},
|
|
1068
1071
|
"rooms": {
|
|
@@ -14,15 +14,23 @@ import { Button, Image, Text, Box, WrapItem, Stack } from '@chakra-ui/react';
|
|
|
14
14
|
import { IconMenuWithMove, MoreHorizontal } from '../../../components';
|
|
15
15
|
import { DocIcon } from '../../../assets/images';
|
|
16
16
|
import { fileTypes, getFileExtension } from '../../../helpers';
|
|
17
|
+
import { useDisplayFiles } from '../../../hooks';
|
|
17
18
|
export const GridFile = (_a) => {
|
|
18
19
|
var { menu = [], onClick, onMove } = _a, props = __rest(_a, ["menu", "onClick", "onMove"]);
|
|
19
20
|
const { _id, title, updatedAt, files = [], receipt, report } = props;
|
|
20
21
|
const fileExtension = getFileExtension(files, !!receipt);
|
|
22
|
+
// Real image thumbnail (empty string for non-images); falls back to the icon.
|
|
23
|
+
const { imageUrl } = useDisplayFiles({ files, title });
|
|
24
|
+
const typeIcon = report && report.length > 0 && !receipt
|
|
25
|
+
? DocIcon
|
|
26
|
+
: fileTypes[fileExtension] || DocIcon;
|
|
21
27
|
const itemForm = {
|
|
22
28
|
_id,
|
|
23
29
|
name: title || '',
|
|
24
30
|
updatedAt,
|
|
25
31
|
icon: fileTypes[fileExtension] || DocIcon,
|
|
26
32
|
};
|
|
27
|
-
return (_jsxs(WrapItem, { maxW: "7rem", position: "relative", children: [_jsx(Box, { position: "absolute", top: "0", right: "1", zIndex: "docked", children: _jsx(IconMenuWithMove, { disabled: menu.length < 1 ? true : false, icon: _jsx(MoreHorizontal, { size: 28 }), itemForm: itemForm, menuItems: menu, onMove: () => onMove(itemForm) }) }), _jsx(Button, { variant: "folder", px: "base", pb: "base", pt: "6", onClick: () => onClick(props), children: _jsxs(Stack, { spacing: "1", align: "center", children: [_jsx(Image, { src:
|
|
33
|
+
return (_jsxs(WrapItem, { maxW: "7rem", position: "relative", children: [_jsx(Box, { position: "absolute", top: "0", right: "1", zIndex: "docked", children: _jsx(IconMenuWithMove, { disabled: menu.length < 1 ? true : false, icon: _jsx(MoreHorizontal, { size: 28 }), itemForm: itemForm, menuItems: menu, onMove: () => onMove(itemForm) }) }), _jsx(Button, { variant: "folder", px: "base", pb: "base", pt: "6", onClick: () => onClick(props), children: _jsxs(Stack, { spacing: "1", align: "center", children: [_jsx(Image, Object.assign({ src: imageUrl || typeIcon, fallbackSrc: typeIcon }, (imageUrl
|
|
34
|
+
? { boxSize: '72px', objectFit: 'cover', borderRadius: 'base' }
|
|
35
|
+
: { w: '46px', h: '49px' }), { alt: fileExtension, transition: "all 0.2s ease-in-out" })), _jsxs(Box, { children: [_jsx(Text, { isTruncated: true, maxWidth: "5rem", fontSize: "sm", children: title }), _jsx(Text, { variant: "date", children: updatedAt })] })] }) })] }));
|
|
28
36
|
};
|
|
@@ -14,15 +14,23 @@ import { Image, Text, Box, Flex } from '@chakra-ui/react';
|
|
|
14
14
|
import { IconMenuWithMove, MoreHorizontal } from '../../../components';
|
|
15
15
|
import { DocIcon } from '../../../assets/images';
|
|
16
16
|
import { fileTypes, getFileExtension } from '../../../helpers';
|
|
17
|
+
import { useDisplayFiles } from '../../../hooks';
|
|
17
18
|
export const ListFile = (_a) => {
|
|
18
19
|
var { menu = [], onClick, onMove } = _a, props = __rest(_a, ["menu", "onClick", "onMove"]);
|
|
19
20
|
const { _id, title, updatedAt, files = [], receipt, report } = props;
|
|
20
21
|
const fileExtension = getFileExtension(files, !!receipt);
|
|
22
|
+
// Real image thumbnail (empty string for non-images); falls back to the icon.
|
|
23
|
+
const { imageUrl } = useDisplayFiles({ files, title });
|
|
24
|
+
const typeIcon = report && report.length > 0 && !receipt
|
|
25
|
+
? DocIcon
|
|
26
|
+
: fileTypes[fileExtension] || DocIcon;
|
|
21
27
|
const itemForm = {
|
|
22
28
|
_id,
|
|
23
29
|
name: title || '',
|
|
24
30
|
updatedAt,
|
|
25
31
|
icon: fileTypes[fileExtension] || DocIcon,
|
|
26
32
|
};
|
|
27
|
-
return (_jsx(Box, { bg: "neutral.white", w: "100%", transition: "all 0.2s ease-in-out", _hover: { bg: 'lightGreen.1' }, children: _jsxs(Flex, { children: [_jsxs(Flex, { gap: "base", p: "base", as: "button", flex: "1", onClick: () => onClick(props), children: [_jsx(Image, { src:
|
|
33
|
+
return (_jsx(Box, { bg: "neutral.white", w: "100%", transition: "all 0.2s ease-in-out", _hover: { bg: 'lightGreen.1' }, children: _jsxs(Flex, { children: [_jsxs(Flex, { gap: "base", p: "base", as: "button", flex: "1", onClick: () => onClick(props), children: [_jsx(Image, Object.assign({ src: imageUrl || typeIcon, fallbackSrc: typeIcon }, (imageUrl
|
|
34
|
+
? { boxSize: '40px', objectFit: 'cover', borderRadius: 'base' }
|
|
35
|
+
: { minW: '32px', h: 'auto' }), { alt: fileExtension, transition: "all 0.2s ease-in-out" })), _jsxs(Box, { mt: "-1", children: [_jsx(Text, { variant: "date", textTransform: "uppercase", textAlign: "left", children: fileExtension === '' ? 'Doc' : fileExtension }), _jsx(Text, { textOverflow: "ellipsis", noOfLines: 1, fontSize: "sm", textAlign: "left", children: title })] })] }), _jsxs(Flex, { align: "center", gap: "2", h: "fit-content", p: "1", pr: "base", children: [_jsx(Text, { variant: "date", w: "fit-content", children: updatedAt }), _jsx(IconMenuWithMove, { disabled: menu.length < 1 ? true : false, icon: _jsx(MoreHorizontal, { size: 28 }), itemForm: itemForm, menuItems: menu, onMove: () => onMove(itemForm) })] })] }) }));
|
|
28
36
|
};
|
|
@@ -23,7 +23,7 @@ export const DynamicForm = (_a) => {
|
|
|
23
23
|
if (searching) {
|
|
24
24
|
return _jsx(SearchItemLoader, {});
|
|
25
25
|
}
|
|
26
|
-
return (_jsxs(Stack, { bg:
|
|
26
|
+
return (_jsxs(Stack, { bg: props.style === 'wizard' ? 'transparent' : 'lightBlue.1', spacing: "0", h: "full", overflowX: props.style === 'wizard' ? 'visible' : 'hidden', children: [showTitle && (_jsx(Box, { px: "base", pt: "4", pb: "2", borderBottom: "1px dashed", borderColor: "lightBlue.6", children: _jsx(Text, { fontFamily: "secondary", children: title !== null && title !== void 0 ? title : t('forms.itemDetails') }) })), _jsx(FormProvider, Object.assign({}, form, { children: _jsx(_Fragment, { children: visibleFields === null || visibleFields === void 0 ? void 0 : visibleFields.map((field) => {
|
|
27
27
|
const { comments, canBeHidden, children, description, icon, id, name, label, options, type, value, } = field;
|
|
28
28
|
const baseProps = {
|
|
29
29
|
id,
|
|
@@ -4,7 +4,7 @@ import { Plus } from '../../../components';
|
|
|
4
4
|
import { colors } from '../../../theme/colors';
|
|
5
5
|
export const HiddenField = ({ disabled, h = '80px', icon, id, isActive, name, onClick, showPlusIcon = false, }) => {
|
|
6
6
|
const handleClick = () => onClick(id);
|
|
7
|
-
return (_jsxs(Box, { position: "relative", children: [_jsxs(Center, { as: "button", disabled: disabled, bg: "neutral.white", borderRadius: "4px", w: "100%", h: h, boxShadow: "md", flexDirection: "column", onClick: handleClick, gap: "1", transition: "all .2s ease-in-out", border: "1px solid", borderColor: isActive ? 'blue.1' : 'transparent', _hover: {
|
|
7
|
+
return (_jsxs(Box, { position: "relative", children: [_jsxs(Center, { as: "button", disabled: disabled, bg: "neutral.white", borderRadius: "4px", w: "100%", h: h, boxShadow: "md", flexDirection: "column", onClick: handleClick, gap: "1", py: "2", px: "1", transition: "all .2s ease-in-out", border: "1px solid", borderColor: isActive ? 'blue.1' : 'transparent', _hover: {
|
|
8
8
|
borderColor: 'blue.1',
|
|
9
9
|
}, _disabled: {
|
|
10
10
|
opacity: 0.5,
|
|
@@ -13,5 +13,5 @@ export const HiddenField = ({ disabled, h = '80px', icon, id, isActive, name, on
|
|
|
13
13
|
},
|
|
14
14
|
}, _active: {
|
|
15
15
|
boxShadow: 'md',
|
|
16
|
-
}, children: [_jsx(Image, { h: "
|
|
16
|
+
}, children: [_jsx(Center, { flex: "1", children: _jsx(Image, { h: "28px", w: "auto", maxW: "36px", src: icon }) }), _jsx(Text, { fontFamily: "primary", color: "gray.3", textTransform: "uppercase", fontSize: "12px", noOfLines: 2, overflow: "hidden", lineHeight: "1", width: "100%", children: name })] }), showPlusIcon && (_jsx(Box, { position: "absolute", top: "1", left: "1", children: _jsx(Plus, { size: 14, stroke: colors.blue[3] }) }))] }));
|
|
17
17
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Stack } from '@chakra-ui/react';
|
|
3
|
-
import { WizardTextBody, WizardInitialOptions, WizardStepOptions, } from '../../../../components';
|
|
3
|
+
import { WizardTextBody, WizardInitialOptions, WizardStepOptions, WizardSelectCard, } from '../../../../components';
|
|
4
4
|
export const HomeInitialSetup = ({ fields, callback, style }) => {
|
|
5
5
|
// const isWizard = style === 'wizard'
|
|
6
6
|
return (_jsx(Stack, { bg: "neutral.white", spacing: { base: '6', md: '0' }, children: fields === null || fields === void 0 ? void 0 : fields.map(({ children = [], id, label = '', type, value, description }) => {
|
|
@@ -11,6 +11,8 @@ export const HomeInitialSetup = ({ fields, callback, style }) => {
|
|
|
11
11
|
return (_jsx(WizardInitialOptions, { form: children, title: String(value), callback: callback, style: style }, id));
|
|
12
12
|
case 'home-wizard-step-options':
|
|
13
13
|
return (_jsx(WizardStepOptions, { form: children, title: String(value), callback: callback, style: style }, id));
|
|
14
|
+
case 'home-wizard-select-card':
|
|
15
|
+
return (_jsx(WizardSelectCard, { form: children, title: String(value), callback: callback, style: style }, id));
|
|
14
16
|
default:
|
|
15
17
|
return null;
|
|
16
18
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createElement as _createElement } from "react";
|
|
3
3
|
import { Box } from '@chakra-ui/react';
|
|
4
|
-
import { ReadOnlyAppliances, ReadOnlyCollapsible, ReadOnlyDate, ReadOnlyGrid, ReadOnlyGroup, ReadOnlyInput, ReadOnlyNotes, ReadOnlyRating, ReadOnlyTextArea, } from '../../../components';
|
|
4
|
+
import { ReadOnlyAppliances, ReadOnlyCollapsible, ReadOnlyDate, ReadOnlyGrid, ReadOnlyGroup, ReadOnlyInput, ReadOnlyHistory, ReadOnlyNotes, ReadOnlyOverview, ReadOnlyPurchaseDetails, ReadOnlyRating, ReadOnlyTextArea, ReadOnlyWarrantyBanner, } from '../../../components';
|
|
5
5
|
import { fieldIcons } from '../../../helpers';
|
|
6
6
|
/**
|
|
7
7
|
* Coerce a field value into something safe to render. A malformed value that
|
|
@@ -26,7 +26,17 @@ function toSafeValue(value) {
|
|
|
26
26
|
return value;
|
|
27
27
|
}
|
|
28
28
|
export const ReadOnlyDynamicForm = ({ form: fields, onClick, onEdit, }) => {
|
|
29
|
-
return (
|
|
29
|
+
return (
|
|
30
|
+
// `overflow="auto"`, not `"scroll"`. `scroll` reserves a scrollbar gutter on
|
|
31
|
+
// BOTH axes whether or not there is anything to scroll — measured at 15px
|
|
32
|
+
// each in Chrome with classic (non-overlay) scrollbars. That gutter is
|
|
33
|
+
// inside the box, so every field rendered here stops 15px short of the
|
|
34
|
+
// panel's right edge and a dead 15px band runs along the bottom, which is
|
|
35
|
+
// what showed up as the item card and warranty banner "not filling the
|
|
36
|
+
// panel". Nothing in this form scrolls sideways, so the horizontal gutter
|
|
37
|
+
// was pure loss. `auto` shows each bar only when that axis actually
|
|
38
|
+
// overflows and reserves nothing otherwise.
|
|
39
|
+
_jsx(Box, { bg: "lightBlue.1", overflow: "auto", children: fields === null || fields === void 0 ? void 0 : fields.map((field) => {
|
|
30
40
|
const { children = [], icon, id, name, type } = field;
|
|
31
41
|
const value = toSafeValue(field.value);
|
|
32
42
|
const baseProps = {
|
|
@@ -51,7 +61,7 @@ export const ReadOnlyDynamicForm = ({ form: fields, onClick, onEdit, }) => {
|
|
|
51
61
|
case 'textarea':
|
|
52
62
|
return (_createElement(ReadOnlyTextArea, Object.assign({}, baseProps, { key: `${id}-${name}-${value}-${type}` })));
|
|
53
63
|
case 'grid':
|
|
54
|
-
return (_jsx(ReadOnlyGrid, { onClick: onClick, children: children }, id));
|
|
64
|
+
return (_jsx(ReadOnlyGrid, { onClick: onClick, borderBottom: "none", children: children }, id));
|
|
55
65
|
case 'group':
|
|
56
66
|
return _jsx(ReadOnlyGroup, { children: children }, id);
|
|
57
67
|
case 'appliances':
|
|
@@ -60,6 +70,14 @@ export const ReadOnlyDynamicForm = ({ form: fields, onClick, onEdit, }) => {
|
|
|
60
70
|
return _createElement(ReadOnlyCollapsible, Object.assign({}, field, { key: id }));
|
|
61
71
|
case 'notes':
|
|
62
72
|
return _createElement(ReadOnlyNotes, Object.assign({}, field, { key: id }));
|
|
73
|
+
case 'warranty':
|
|
74
|
+
return _createElement(ReadOnlyWarrantyBanner, Object.assign({}, field, { key: id }));
|
|
75
|
+
case 'purchase':
|
|
76
|
+
return (_createElement(ReadOnlyPurchaseDetails, Object.assign({}, field, { key: id, onClick: onClick })));
|
|
77
|
+
case 'overview':
|
|
78
|
+
return _createElement(ReadOnlyOverview, Object.assign({}, field, { key: id }));
|
|
79
|
+
case 'history':
|
|
80
|
+
return _createElement(ReadOnlyHistory, Object.assign({}, field, { key: id }));
|
|
63
81
|
default:
|
|
64
82
|
return null;
|
|
65
83
|
}
|
|
@@ -1,24 +1,67 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Text, Flex, Stack, IconButton, Box, Image, SimpleGrid, Grid } from '@chakra-ui/react';
|
|
4
|
+
import { Edit } from '../../../../../components';
|
|
4
5
|
import { colors } from '../../../../../theme/colors';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
6
|
+
import { formatCurrency } from '../../../../../utils';
|
|
7
|
+
// Dashed rule between sections (XD: light gray dashed).
|
|
8
|
+
const DashedRule = () => (_jsx(Box, { borderBottom: "1px dashed", borderColor: "lightGray.2" }));
|
|
9
|
+
// Brand / Model# / Serial# row — label #6C7679, value #464646 (XD).
|
|
10
|
+
//
|
|
11
|
+
// The label column sizes to its content with a floor, rather than taking a
|
|
12
|
+
// fixed 35%: a real label is "Brand/Manufacturer:" (a schema key in ~50 places
|
|
13
|
+
// across the platform, so it cannot simply be shortened), and 35% of a narrow
|
|
14
|
+
// drawer is not wide enough for it. The percentage broke it mid-word into
|
|
15
|
+
// "Brand/Manufact" + "urer:". `keep-all` stops the mid-word break outright,
|
|
16
|
+
// so a label that still outgrows the column wraps at a natural boundary.
|
|
17
|
+
// Values arrive from different extractors with inconsistent casing — a brand
|
|
18
|
+
// comes back "Maytag", a product type "front-load washing machine" — so the
|
|
19
|
+
// column reads as a ransom note. Capitalize the FIRST character only and leave
|
|
20
|
+
// the rest of the string untouched: that makes the column consistent without
|
|
21
|
+
// rewriting the data, and keeps model numbers like "NC501" or "DCC-3400"
|
|
22
|
+
// exactly as extracted (title-casing them would produce "Nc501").
|
|
23
|
+
const leadCap = (s) => s.length > 0 ? s[0].toUpperCase() + s.slice(1) : s;
|
|
24
|
+
// Renders as TWO grid cells rather than a self-contained row, so every label
|
|
25
|
+
// shares one column and every value starts on the same left edge.
|
|
26
|
+
//
|
|
27
|
+
// Each row previously sized its own label independently, so the value column
|
|
28
|
+
// was ragged — the longest label ("Avg Retail Price Range:") pushed its own
|
|
29
|
+
// value right while the others sat further left. A fixed percentage was the
|
|
30
|
+
// original spec and broke the opposite way, wrapping "Brand/Manufacturer:"
|
|
31
|
+
// mid-word. A shared `max-content` column solves both: it is exactly as wide
|
|
32
|
+
// as the longest label, so nothing wraps and everything aligns.
|
|
33
|
+
const DetailRow = ({ label, value }) => (_jsxs(_Fragment, { children: [_jsx(Text, { wordBreak: "keep-all", fontFamily: "secondary", fontSize: "14px", lineHeight: "18px", color: "#6C7679", children: label }), _jsx(Text, { fontFamily: "secondary", fontSize: "14px", lineHeight: "18px", color: "gray.3", children: value != null ? leadCap(String(value)) : '' })] }));
|
|
34
|
+
// A value-row amount is currency-formatted only when it IS a single number.
|
|
35
|
+
//
|
|
36
|
+
// Catalog-resolved prices arrive as RANGE strings ("$229-$249") because that is
|
|
37
|
+
// what can honestly be established for a model. formatCurrency runs Number() on
|
|
38
|
+
// its input, and Number("$229-$249") is NaN, so formatting one prints "$NaN" on
|
|
39
|
+
// the owner's card. A non-numeric amount is already human-readable — render it
|
|
40
|
+
// as-is rather than mangling it.
|
|
41
|
+
const formatValueAmount = (value) => {
|
|
42
|
+
if (value == null || value === '')
|
|
43
|
+
return '';
|
|
44
|
+
const numeric = typeof value === 'number' ? value : Number(String(value).replace(/[$,\s]/g, ''));
|
|
45
|
+
return Number.isFinite(numeric)
|
|
46
|
+
? formatCurrency({ value: numeric })
|
|
47
|
+
: String(value);
|
|
48
|
+
};
|
|
49
|
+
// Retail Price / Est Replacement Cost — label left #6C7679, value right #464646.
|
|
50
|
+
const ValueRow = ({ label, value, bold, }) => (_jsxs(Flex, { justify: "space-between", children: [_jsx(Text, { fontFamily: "secondary", fontSize: "16px", lineHeight: "20px", color: "#6C7679", children: label }), _jsx(Text, { fontFamily: "secondary", fontSize: "16px", lineHeight: "20px", color: "gray.3", fontWeight: bold ? 'bold' : 'normal', children: formatValueAmount(value) })] }));
|
|
51
|
+
export const ReadOnlyAppliances = ({ description, id, name, children = [], onEdit, value, }) => {
|
|
52
|
+
var _a;
|
|
53
|
+
const imageField = children.find(({ type }) => type === 'images');
|
|
54
|
+
const images = (_a = imageField === null || imageField === void 0 ? void 0 : imageField.value) !== null && _a !== void 0 ? _a : [];
|
|
55
|
+
// The chosen thumbnail is stored; the displayed image is DERIVED from it.
|
|
56
|
+
//
|
|
57
|
+
// `useState(images[0])` captured the first image only on the first render —
|
|
58
|
+
// and images arrive after that render, so the card kept showing an empty
|
|
59
|
+
// <Image> (a broken-picture box) until something else forced a re-render.
|
|
60
|
+
// Deriving means there is no second copy of "which image" to go stale, and a
|
|
61
|
+
// selection that is no longer in the list falls back instead of blanking.
|
|
62
|
+
const [chosenImage, setChosenImage] = useState(undefined);
|
|
63
|
+
const mainImage = chosenImage && images.includes(chosenImage) ? chosenImage : images[0];
|
|
64
|
+
const detailFields = children.filter(({ type }) => type === 'text');
|
|
65
|
+
const valueFields = children.filter(({ type }) => type === 'currency');
|
|
66
|
+
return (_jsxs(Stack, { spacing: "base", p: "base", bg: "neutral.white", mt: "2px", children: [(name || onEdit) && (_jsxs(Flex, { justify: "space-between", align: "center", w: "full", children: [_jsx(Text, { fontFamily: "primary", fontSize: "12px", letterSpacing: "0", color: "#525458", textTransform: "uppercase", children: name }), onEdit && (_jsx(IconButton, { "aria-label": "Edit appliance", variant: "ghost", w: "fit-content", minW: "auto", h: "auto", p: "0", flexShrink: 0, icon: _jsx(Edit, { size: 18, stroke: colors.blue[3] }), onClick: () => onEdit(id) }))] })), _jsxs(Flex, { gap: "base", align: "stretch", children: [_jsxs(Flex, { direction: "column", gap: "base", flexShrink: 0, w: "174px", children: [_jsx(Image, { src: mainImage, alt: "home item", boxSize: "174px", objectFit: "cover" }), images.length > 0 && (_jsx(SimpleGrid, { columns: 4, spacing: "2", children: images.map((image) => (_jsx(Box, { as: "button", backgroundImage: image, backgroundSize: "cover", backgroundPosition: "center", boxSize: "34px", onClick: () => setChosenImage(image) }, image))) }))] }), _jsxs(Stack, { flex: "1", spacing: "base", children: [_jsxs(Stack, { spacing: "13px", children: [_jsx(Text, { fontFamily: "primary", fontWeight: "600", fontSize: "22px", lineHeight: "26px", letterSpacing: "0", color: "gray.3", children: value }), _jsx(Text, { fontFamily: "secondary", fontSize: "14px", lineHeight: "15px", color: "gray.3", children: description })] }), _jsx(DashedRule, {}), detailFields.length > 0 && (_jsx(Grid, { templateColumns: "max-content 1fr", columnGap: "base", rowGap: "0", alignItems: "start", children: detailFields.map((field) => (_jsx(DetailRow, { label: field.name ? `${field.name}:` : undefined, value: field.value }, `${field.id}-${field.name}`))) })), valueFields.length > 0 && (_jsxs(_Fragment, { children: [_jsx(DashedRule, {}), _jsx(Stack, { spacing: "0", children: valueFields.map((field, i) => (_jsx(ValueRow, { label: field.name, value: field.value, bold: i === valueFields.length - 1 }, `${field.id}-${field.name}`))) })] }))] })] })] }));
|
|
24
67
|
};
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Text, Stack,
|
|
2
|
+
import { Text, Stack, Box, Flex } from '@chakra-ui/react';
|
|
3
3
|
import { HiddenField } from '../../../../../components';
|
|
4
4
|
import { fieldIcons } from '../../../../../helpers';
|
|
5
|
+
// Care & Guidelines column: hugs its content (content-width) so the Parts
|
|
6
|
+
// column can fill the remaining width to the right of the 13px separator.
|
|
7
|
+
// Tiles are fixed 75px squares (HiddenField's own `h` prop — not modified).
|
|
5
8
|
export const ReadOnlyGuidelines = ({ name, children, onClick, }) => {
|
|
6
|
-
return (_jsxs(Stack, { spacing: "base",
|
|
9
|
+
return (_jsxs(Stack, { spacing: "base", width: "fit-content", flexShrink: 0, children: [_jsx(Text, { fontFamily: "primary", fontSize: "12px", color: "gray.3", textTransform: "uppercase", children: name }), _jsx(Flex, { flexWrap: "wrap", gap: "base", children: children === null || children === void 0 ? void 0 : children.map((child) => {
|
|
7
10
|
const { id, icon, value } = child;
|
|
8
11
|
const btnIcon = icon ? fieldIcons[icon] : '';
|
|
9
|
-
return (_jsx(HiddenField, { id: id, icon: btnIcon, name: value, onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(id) }, id));
|
|
12
|
+
return (_jsx(Box, { w: "75px", children: _jsx(HiddenField, { id: id, h: "75px", icon: btnIcon, name: value, onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(id) }) }, id));
|
|
10
13
|
}) })] }));
|
|
11
14
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Flex, Stack, Text } from '@chakra-ui/react';
|
|
3
|
+
import { DatePennant, HistoryCard } from '../../../../../components';
|
|
4
|
+
import { fieldIcons } from '../../../../../helpers';
|
|
5
|
+
import { formatCurrency } from '../../../../../utils';
|
|
6
|
+
// label (left #6C7679) + value (right #464646) — Brand / Model# rows (XD "Card").
|
|
7
|
+
const Row = ({ label, value }) => (_jsxs(Flex, { gap: "base", children: [_jsx(Text, { minW: "70px", fontFamily: "secondary", fontSize: "14px", lineHeight: "20px", color: "#6C7679", children: label }), _jsx(Text, { fontFamily: "secondary", fontSize: "14px", lineHeight: "20px", color: "gray.3", children: value != null ? String(value) : '' })] }));
|
|
8
|
+
// A single history event on the timeline: a date pennant (color per event type)
|
|
9
|
+
// joined by a node to the core HistoryCard. `label` = the pennant date,
|
|
10
|
+
// `accentColor` = the pennant color. Body is derived from children: an optional
|
|
11
|
+
// bold heading (value, e.g. a service company), Brand/Model-style rows for named
|
|
12
|
+
// text, plain lines for unnamed (address), a currency child as the attachment,
|
|
13
|
+
// an images child as the logo.
|
|
14
|
+
export const ReadOnlyHistory = ({ name, value, label, accentColor, children = [], }) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const image = (_a = children.find(({ type }) => type === 'images')) === null || _a === void 0 ? void 0 : _a.value;
|
|
17
|
+
const attach = children.find(({ type }) => type === 'currency');
|
|
18
|
+
const textFields = children.filter(({ type }) => type === 'text');
|
|
19
|
+
const heading = value != null && value !== '' ? String(value) : '';
|
|
20
|
+
const color = accentColor || '#1E6388';
|
|
21
|
+
// Honesty: nothing credible to show → render nothing.
|
|
22
|
+
if (!name && !heading && textFields.length === 0 && !attach)
|
|
23
|
+
return null;
|
|
24
|
+
const attachment = attach
|
|
25
|
+
? {
|
|
26
|
+
// Data-driven file-type icon (e.g. 'pdf'); none if unspecified.
|
|
27
|
+
icon: attach.icon ? fieldIcons[attach.icon] : undefined,
|
|
28
|
+
label: attach.name,
|
|
29
|
+
amount: attach.value != null && attach.value !== ''
|
|
30
|
+
? formatCurrency({ value: attach.value })
|
|
31
|
+
: undefined,
|
|
32
|
+
}
|
|
33
|
+
: undefined;
|
|
34
|
+
return (_jsx(Box, { pl: "base", pr: "base", pt: "base", _last: { pb: 'base' }, children: _jsxs(Flex, { align: "flex-start", children: [_jsxs(Flex, { align: "center", pt: "12px", flexShrink: 0, children: [_jsx(DatePennant, { date: label, color: color }), _jsx(Box, { boxSize: "10px", borderRadius: "full", bg: "neutral.white", border: "2px solid", borderColor: color, ml: "0", zIndex: 2 })] }), _jsx(Box, { flex: "1", ml: "6px", children: _jsx(HistoryCard, { title: name, image: image, imagePosition: heading ? 'right' : 'left', attachment: attachment, children: _jsxs(Stack, { spacing: "0", children: [heading && (_jsx(Text, { fontFamily: "secondary", fontWeight: "bold", fontSize: "16px", lineHeight: "22px", color: "gray.3", children: heading })), textFields.map((field) => field.name ? (_jsx(Row, { label: `${field.name}:`, value: field.value }, field.id)) : (_jsx(Text, { fontFamily: "secondary", fontSize: "14px", lineHeight: "18px", color: "#3E4045", children: field.value != null ? String(field.value) : '' }, field.id)))] }) }) })] }) }));
|
|
35
|
+
};
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Text, Stack, Grid, Box } from '@chakra-ui/react';
|
|
2
|
+
import { Text, Stack, Grid, Box, Flex, Link } from '@chakra-ui/react';
|
|
3
3
|
import { HiddenField } from '../../../../../components';
|
|
4
4
|
import { fieldIcons } from '../../../../../helpers';
|
|
5
|
+
// Parts & Accessories column: fills the width to the right of the separator
|
|
6
|
+
// (flex="1"), so "View All" sits at the right edge. The 13px on the LEFT of the
|
|
7
|
+
// separator is the parent Flex `gap="base"` (=13px); the 13px on the RIGHT is
|
|
8
|
+
// this box's `pl="13px"`. Tiles are fixed 75px squares, three across, wrapping
|
|
9
|
+
// in threes. Icons are data-driven (each part's `icon` → the appliance icon).
|
|
5
10
|
export const ReadOnlyItemRelated = ({ name, children, onClick, }) => {
|
|
6
|
-
return (_jsx(Box, { borderLeft: "1px solid", borderColor: "lightBlue.
|
|
11
|
+
return (_jsx(Box, { flex: "1", borderLeft: "1px solid", borderColor: "lightBlue.5", pl: "13px", children: _jsxs(Stack, { spacing: "base", children: [_jsxs(Flex, { justify: "space-between", align: "center", gap: "base", children: [_jsx(Text, { fontFamily: "primary", fontSize: "12px", color: "gray.3", textTransform: "uppercase", children: name }), _jsx(Link, { fontFamily: "secondary", fontSize: "14px", fontWeight: "normal", color: "#2487C5", flexShrink: 0, onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick('view-all'), children: "View All" })] }), _jsx(Grid, { templateColumns: "repeat(4, 75px)", gap: "base", children: children === null || children === void 0 ? void 0 : children.map((child) => {
|
|
7
12
|
const { id, icon, value } = child;
|
|
8
13
|
const btnIcon = icon ? fieldIcons[icon] : '';
|
|
9
|
-
return (_jsx(HiddenField, { id: id, icon: btnIcon, name: value, onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(id) }, id));
|
|
14
|
+
return (_jsx(HiddenField, { id: id, h: "75px", icon: btnIcon, name: value, onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(id) }, id));
|
|
10
15
|
}) })] }) }));
|
|
11
16
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Accordion, AccordionButton, AccordionItem, AccordionPanel, Box, Flex, ListItem, Text, UnorderedList, } from '@chakra-ui/react';
|
|
3
|
+
import { ChevronRight } from '../../../../../components';
|
|
4
|
+
// A Specs collapsible section — XD assembled Specs artboard. Exact spec:
|
|
5
|
+
// white card, 3px radius, shadow rgba(0,0,0,.16) 0 3px 6px; header padded
|
|
6
|
+
// 13px (top/sides) and 6.5px (bottom); title Poppins Regular 12px #525458
|
|
7
|
+
// uppercase + a blue circle chevron; body = bulleted list (Assistant 12px
|
|
8
|
+
// #464646). Built directly on Accordion (the shared Collapsible can't express
|
|
9
|
+
// this padding/radius/shadow).
|
|
10
|
+
export const ReadOnlyOverview = ({ name = '', children = [] }) => {
|
|
11
|
+
const bullets = children.filter((c) => c.value != null && c.value !== '');
|
|
12
|
+
// Honesty: no bullets → render nothing (never fabricate specs).
|
|
13
|
+
if (bullets.length === 0)
|
|
14
|
+
return null;
|
|
15
|
+
return (_jsx(Accordion, { allowToggle: true, bg: "neutral.white", borderRadius: "3px", boxShadow: "0 3px 6px rgba(0, 0, 0, 0.16)", children: _jsx(AccordionItem, { border: "none", children: ({ isExpanded }) => (_jsxs(_Fragment, { children: [_jsx(AccordionButton, { p: "base", _hover: { bg: 'transparent' }, _focus: { outline: 'none' }, children: _jsxs(Flex, { flex: "1", align: "center", justify: "space-between", children: [_jsx(Text, { fontFamily: "primary", fontSize: "14px", color: "#525458", textTransform: "uppercase", children: name }), _jsx(Box, { rounded: "full", border: "1px solid", borderColor: "blue.3", padding: "1", transition: "all .2s ease-in-out", transform: isExpanded ? 'rotate(-90deg)' : 'rotate(0)', children: _jsx(ChevronRight, {}) })] }) }), _jsx(AccordionPanel, { px: "13px", pb: "13px", pt: "0", children: _jsx(UnorderedList, { spacing: "base", m: "0", pl: "1.1em", children: bullets.map((bullet) => (_jsx(ListItem, { fontFamily: "secondary", fontSize: "14px", lineHeight: "1.4", color: "gray.3", children: String(bullet.value) }, bullet.id))) }) })] })) }) }));
|
|
16
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text, Flex, Stack, Box, Image, Link } from '@chakra-ui/react';
|
|
3
|
+
import { formatCurrency } from '../../../../../utils';
|
|
4
|
+
// Purchase Details block — XD "Purchase Details" (500×178). Retailer logo
|
|
5
|
+
// (128px square) + retailer name, then a purchase column (Purchased / Payment)
|
|
6
|
+
// and, past a vertical dashed divider, a totals column (Price / Tax / Total).
|
|
7
|
+
// Fonts/colors from the XD character styles:
|
|
8
|
+
// header "PURCHASE DETAILS" Poppins Regular 12px #464646 uppercase
|
|
9
|
+
// "View Receipt" Assistant Regular 14px #2488C6
|
|
10
|
+
// retailer label Assistant Regular 14px #6C7679
|
|
11
|
+
// retailer name Poppins SemiBold 18px #464646
|
|
12
|
+
// row label Assistant Regular 14px #6C7679
|
|
13
|
+
// row value Assistant Regular 14px #464646 (Total: Bold)
|
|
14
|
+
// label (left, #6C7679) + value (right, #464646). `bold` for the Total value.
|
|
15
|
+
const Row = ({ label, value, bold, }) => (_jsxs(Flex, { justify: "space-between", gap: "base", children: [_jsx(Text, { fontFamily: "secondary", fontSize: "14px", lineHeight: "20px", color: "#6C7679", children: label }), _jsx(Text, { fontFamily: "secondary", fontSize: "14px", lineHeight: "20px", color: "gray.3", fontWeight: bold ? 'bold' : 'normal', children: value != null ? String(value) : '' })] }));
|
|
16
|
+
export const ReadOnlyPurchaseDetails = ({ id, name, link, children = [], onClick, }) => {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const logo = (_a = children.find(({ type }) => type === 'images')) === null || _a === void 0 ? void 0 : _a.value;
|
|
19
|
+
const retailer = children.find((c) => c.name === 'Retailer');
|
|
20
|
+
const detailFields = children.filter(({ type, name: n }) => (type === 'text' || type === 'date') && n !== 'Retailer');
|
|
21
|
+
const valueFields = children.filter(({ type }) => type === 'currency');
|
|
22
|
+
// Honesty: nothing credible to show → render nothing (never fabricate).
|
|
23
|
+
if (!retailer && !logo && valueFields.length === 0)
|
|
24
|
+
return null;
|
|
25
|
+
return (_jsxs(Stack, { spacing: "base", p: "base", bg: "neutral.white", mt: "2px", children: [_jsxs(Flex, { justify: "space-between", align: "center", w: "full", children: [_jsx(Text, { fontFamily: "primary", fontSize: "12px", letterSpacing: "0", color: "gray.3", textTransform: "uppercase", children: name }), link && (_jsx(Link, { fontFamily: "secondary", fontSize: "14px", fontWeight: "normal", color: "#2488C6", onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(id), children: "View Receipt" }))] }), _jsxs(Flex, { gap: "base", align: "stretch", children: [logo && (_jsx(Image, { src: logo, alt: (retailer === null || retailer === void 0 ? void 0 : retailer.value) || 'retailer', boxSize: "128px", objectFit: "contain", flexShrink: 0 })), _jsxs(Stack, { flex: "1", spacing: "13px", children: [retailer && (_jsx(Text, { fontFamily: "primary", fontWeight: "600", fontSize: "22px", lineHeight: "26px", letterSpacing: "0", color: "gray.3", mt: "30px", children: String((_b = retailer.value) !== null && _b !== void 0 ? _b : '') })), _jsxs(Flex, { gap: "base", align: "flex-start", children: [detailFields.length > 0 && (_jsx(Stack, { flex: "1", spacing: "0", children: detailFields.map((field) => (_jsx(Row, { label: field.name ? `${field.name}:` : undefined, value: field.value }, `${field.id}-${field.name}`))) })), valueFields.length > 0 && (_jsx(Box, { borderLeft: "1px dashed", borderColor: "lightGray.2", pl: "base", w: "170px", flexShrink: 0, children: _jsx(Stack, { spacing: "0", children: valueFields.map((field, i) => (_jsx(Row, { label: field.name ? `${field.name}:` : undefined, value: field.value != null && field.value !== ''
|
|
26
|
+
? formatCurrency({
|
|
27
|
+
value: field.value,
|
|
28
|
+
})
|
|
29
|
+
: '', bold: i === valueFields.length - 1 }, `${field.id}-${field.name}`))) }) }))] })] })] })] }));
|
|
30
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { t } from 'i18next';
|
|
3
|
+
import { Box, Circle, Flex, Image, Link, Text } from '@chakra-ui/react';
|
|
4
|
+
import { ArrowLeft } from '../../../../../components';
|
|
5
|
+
import { fieldIcons } from '../../../../../helpers';
|
|
6
|
+
import { colors } from '../../../../../theme/colors';
|
|
7
|
+
/**
|
|
8
|
+
* Warranty-status banner. Built to the EXACT CSS from the "Read Only Item" XD
|
|
9
|
+
* (dev/spec mode), under-warranty artboard:
|
|
10
|
+
* container: height 76px, background #F2F9F2, no border, no radius
|
|
11
|
+
* badge circle: 45×45, #E0EBE0, full radius, 10px from the left / centered
|
|
12
|
+
* umbrella: 27×29
|
|
13
|
+
* text: Poppins Regular 16px/20px, letter-spacing 0, #464646, left
|
|
14
|
+
*
|
|
15
|
+
* Only the under-warranty state is designed in the XD. `expired` and `recall`
|
|
16
|
+
* palettes below are PROVISIONAL placeholders (awaiting their own artboards) —
|
|
17
|
+
* flagged so they get exact CSS before shipping, not invented values.
|
|
18
|
+
*
|
|
19
|
+
* HONESTY: `recall` must ONLY be used with REAL recall data (#357) — the banner
|
|
20
|
+
* renders nothing when `value` is empty and never fabricates an alert.
|
|
21
|
+
*/
|
|
22
|
+
// Per-state visuals. `icon` is a `fieldIcons` key and is the SINGLE swap point
|
|
23
|
+
// for each state's glyph — drop the new expired/recall icons in here (one line
|
|
24
|
+
// each) once their assets are registered in `fieldIcons`. Colors reuse existing
|
|
25
|
+
// design-system variants (no new colors): under-warranty = exact XD; expired =
|
|
26
|
+
// neutral gray family; recall = the app's alert color (`error`, same variant as
|
|
27
|
+
// AlertBanner / CreditCardError). Exact XD for expired/recall is still TBD.
|
|
28
|
+
const STATE = {
|
|
29
|
+
underWarranty: { bg: '#F2F9F2', badge: '#E0EBE0', icon: 'warranty' },
|
|
30
|
+
expired: { bg: 'lightGray.1', badge: 'lightGray.2', icon: 'warranty' }, // TODO: swap to the expired icon
|
|
31
|
+
// EXACT CSS from the unknown-warranty XD artboard (Matt, 09-21) — no longer
|
|
32
|
+
// provisional. Light blue reads INFORMATIONAL: deliberately neither the
|
|
33
|
+
// green of "covered" nor the gray of "lapsed", because the point of the
|
|
34
|
+
// state is that we do not know which it is.
|
|
35
|
+
// container #DEEDF7 · badge #BFDCEF · "?" #5F7482 Poppins SemiBold 29px
|
|
36
|
+
unverified: { bg: '#DEEDF7', badge: '#BFDCEF', icon: 'warranty' },
|
|
37
|
+
recall: { bg: 'error.1', badge: 'error.2', icon: 'warranty' }, // TODO: swap to the recall icon
|
|
38
|
+
};
|
|
39
|
+
export const ReadOnlyWarrantyBanner = ({ icon, value,
|
|
40
|
+
// Defaults to the NEUTRAL state, not to "covered". The only production
|
|
41
|
+
// caller spreads field data (ReadOnlyDynamicForm), so a warranty field that
|
|
42
|
+
// arrives without an explicit state used to assert coverage by omission —
|
|
43
|
+
// the same fail-unsafe default as the STATE lookup below. Callers that mean
|
|
44
|
+
// "under warranty" must say so.
|
|
45
|
+
state = 'unverified', link, onAction, actionLabel, }) => {
|
|
46
|
+
var _a;
|
|
47
|
+
// No data → render nothing. Never fabricate a status (critical for recall).
|
|
48
|
+
if (!value)
|
|
49
|
+
return null;
|
|
50
|
+
// Fail SAFE on an unrecognised state: degrade to "we don't know", never to
|
|
51
|
+
// "you are covered". This is not hypothetical — a caller on a NEWER build
|
|
52
|
+
// than the installed package can send a state this copy has no key for (e.g.
|
|
53
|
+
// 'unverified' against 2.60.0), and a green fallback would assert coverage
|
|
54
|
+
// the data cannot support. Neutral is the only defensible default.
|
|
55
|
+
const s = (_a = STATE[state]) !== null && _a !== void 0 ? _a : STATE.unverified;
|
|
56
|
+
// Field-provided icon overrides; otherwise the state's own (swappable) icon.
|
|
57
|
+
const iconKey = icon !== null && icon !== void 0 ? icon : s.icon;
|
|
58
|
+
const bannerIcon = iconKey ? fieldIcons[iconKey] : '';
|
|
59
|
+
// States drawn as a typographic glyph rather than an image asset. Both are
|
|
60
|
+
// punctuation the brand face already carries, so neither needs an icon file.
|
|
61
|
+
const glyph = state === 'recall' ? '!' : state === 'unverified' ? '?' : '';
|
|
62
|
+
return (_jsxs(Flex, { align: "center", gap: "10px", minH: "76px", pl: "10px", pr: "base", bg: s.bg, mt: "2px", children: [_jsx(Flex, { align: "center", justify: "center", flexShrink: 0, boxSize: "45px", borderRadius: "full", bg: s.badge, children: glyph ? (
|
|
63
|
+
// Typographic glyph sized to the internal icon (29px): "!" for
|
|
64
|
+
// recall, "?" for unverified. Recall keeps extra-bold white on its
|
|
65
|
+
// saturated badge; unverified is exact XD — Poppins SemiBold (600)
|
|
66
|
+
// in #5F7482, a desaturated slate that reads on the pale badge
|
|
67
|
+
// without competing with the message.
|
|
68
|
+
_jsx(Text, { fontFamily: "primary", fontWeight: state === 'recall' ? 'extrabold' : '600', fontSize: "29px", lineHeight: "1", color: state === 'recall' ? 'neutral.white' : '#5F7482', children: glyph })) : (bannerIcon && (_jsx(Image, { src: bannerIcon, alt: "warranty status", w: "27px", h: "29px", objectFit: "contain" }))) }), link ? (_jsx(Link, { href: link, isExternal: true, fontFamily: "primary", fontSize: "16px", lineHeight: "20px", letterSpacing: "0", color: "gray.3", sx: { textWrap: 'balance' }, children: String(value) })) : (_jsx(Text, { fontFamily: "primary", fontSize: "16px", lineHeight: "20px", letterSpacing: "0", color: "gray.3", sx: { textWrap: 'balance' }, children: String(value) })), onAction && (_jsx(Circle, { as: "button", type: "button", onClick: onAction, "aria-label": actionLabel !== null && actionLabel !== void 0 ? actionLabel : t('buttons.forward'), size: "40px", bg: "neutral.white", flexShrink: 0, ml: "auto", transition: "all 0.2s ease-in-out", _hover: { boxShadow: 'lg' }, children: _jsx(Box, { transform: "rotate(180deg)", lineHeight: "0", children: _jsx(ArrowLeft, { stroke: colors.blue[2], size: 24 }) }) }))] }));
|
|
69
|
+
};
|
|
@@ -4,4 +4,8 @@ export * from './ReadOnlyGuidelines';
|
|
|
4
4
|
export * from './ReadOnlyHomeItemImages';
|
|
5
5
|
export * from './ReadOnlyHomeItemRating';
|
|
6
6
|
export * from './ReadOnlyHomeItemText';
|
|
7
|
+
export * from './ReadOnlyHistory';
|
|
7
8
|
export * from './ReadOnlyItemRelated';
|
|
9
|
+
export * from './ReadOnlyOverview';
|
|
10
|
+
export * from './ReadOnlyPurchaseDetails';
|
|
11
|
+
export * from './ReadOnlyWarrantyBanner';
|
|
@@ -4,4 +4,8 @@ export * from './ReadOnlyGuidelines';
|
|
|
4
4
|
export * from './ReadOnlyHomeItemImages';
|
|
5
5
|
export * from './ReadOnlyHomeItemRating';
|
|
6
6
|
export * from './ReadOnlyHomeItemText';
|
|
7
|
+
export * from './ReadOnlyHistory';
|
|
7
8
|
export * from './ReadOnlyItemRelated';
|
|
9
|
+
export * from './ReadOnlyOverview';
|
|
10
|
+
export * from './ReadOnlyPurchaseDetails';
|
|
11
|
+
export * from './ReadOnlyWarrantyBanner';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Flex, Tab, TabList, TabPanel, TabPanels, Tabs, } from '@chakra-ui/react';
|
|
3
3
|
export const TabsHeader = ({ onChange, tabList, tabIndex, defaultIndex, rightButton, rightTabList, }) => {
|
|
4
|
-
return (_jsxs(Tabs, { zIndex: "base", variant: "unstyled", onChange: onChange, index: tabIndex, defaultIndex: defaultIndex, h: "100%", children: [_jsx(Box, { bg: "lightBlue.2", children: _jsxs(Flex, { justify: "space-between", children: [_jsx(TabList, { bg: "neutral.white", w: "full", children: tabList === null || tabList === void 0 ? void 0 : tabList.map(({ label }) => (_jsx(CustomTab, { label: label }, label))) }), _jsxs(Flex, { flexShrink: 0, children: [_jsx(TabList, { bg: "neutral.white", w: "full", children: rightTabList === null || rightTabList === void 0 ? void 0 : rightTabList.map(({ label }) => (_jsx(CustomTab, { label: label }, label))) }), rightButton] })] }) }), _jsx(TabPanels, { h: "100%", children: tabList
|
|
4
|
+
return (_jsxs(Tabs, { zIndex: "base", variant: "unstyled", onChange: onChange, index: tabIndex, defaultIndex: defaultIndex, h: "100%", children: [_jsx(Box, { bg: "lightBlue.2", children: _jsxs(Flex, { justify: "space-between", children: [_jsx(TabList, { bg: "neutral.white", w: "full", children: tabList === null || tabList === void 0 ? void 0 : tabList.map(({ label }) => (_jsx(CustomTab, { label: label }, label))) }), _jsxs(Flex, { flexShrink: 0, children: [_jsx(TabList, { bg: "neutral.white", w: "full", children: rightTabList === null || rightTabList === void 0 ? void 0 : rightTabList.map(({ label }) => (_jsx(CustomTab, { label: label }, label))) }), rightButton] })] }) }), _jsx(TabPanels, { h: "100%", children: [...(tabList !== null && tabList !== void 0 ? tabList : []), ...(rightTabList !== null && rightTabList !== void 0 ? rightTabList : [])].map(({ label, component }) => (_jsx(TabPanel, { p: "0", h: "100%", children: component }, label))) })] }));
|
|
5
5
|
};
|
|
6
6
|
const CustomTab = ({ label = '' }) => {
|
|
7
7
|
return (_jsx(Tab, { minW: "1rem", px: "base", py: "0", lineHeight: "10", textTransform: "uppercase", fontWeight: "normal", fontSize: "sm", fontFamily: "primary", color: "blue.2", borderBottom: "3px solid transparent", _hover: { cursor: 'pointer' }, _focus: { outline: 'none' }, _selected: {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface AddDocumentsI {
|
|
2
|
+
title?: string;
|
|
3
|
+
message?: string;
|
|
4
|
+
/** "browse" affordance — the consumer wires the real file picker/dropzone. */
|
|
5
|
+
onBrowse?: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const AddDocuments: ({ title, message, onBrowse, }: AddDocumentsI) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Flex, Link, Stack, Text } from '@chakra-ui/react';
|
|
3
|
+
import { Upload } from '../../components';
|
|
4
|
+
// Add-documents zone atop the History tab — XD "Assembled – 1".
|
|
5
|
+
// Section sits on the dark rail color (#E9EDEF); inside, a 72px dashed drop
|
|
6
|
+
// area (bg rgba(219,236,246,.6), 1px dashed #707070, radius 4px). The message
|
|
7
|
+
// is Assistant 16px #606060; "browse" is a Poppins Medium 16px #2487C5 link.
|
|
8
|
+
export const AddDocuments = ({ title = 'Add Notes, Documents and Service Records', message = 'Drag and drop media here or', onBrowse, }) => (_jsxs(Stack, { spacing: "base", p: "base", bg: "#E9EDEF", children: [_jsx(Text, { fontFamily: "secondary", fontSize: "16px", color: "#606060", children: title }), _jsxs(Flex, { h: "72px", align: "center", justify: "center", gap: "2", bg: "rgba(219, 236, 246, 0.6)", border: "1px dashed", borderColor: "rgba(112, 112, 112, 0.45)", borderRadius: "4px", children: [_jsx(Upload, {}), _jsx(Text, { fontFamily: "secondary", fontSize: "16px", color: "#606060", children: message }), _jsx(Link, { fontFamily: "secondary", fontSize: "16px", color: "#2487C5", onClick: onBrowse, children: "browse" })] })] }));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface DatePennantI {
|
|
2
|
+
/** Display date, e.g. "01 23 2017". */
|
|
3
|
+
date?: string;
|
|
4
|
+
/** Pennant fill — data-driven per event type (a legend maps color→type). */
|
|
5
|
+
color?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const DatePennant: ({ date, color }: DatePennantI) => import("react/jsx-runtime").JSX.Element;
|