Compare commits
6 Commits
feature/ar
...
v0.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
| e8634c396f | |||
| edddf6d857 | |||
| 1276b13fec | |||
| 2aa361e3db | |||
|
|
4cda998bd7 | ||
|
|
3e0e570ff6 |
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "dry-wash",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "dry-wash",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@brojs/cli": "^1.6.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dry-wash",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"description": "<a id=\"readme-top\"></a>",
|
||||
"main": "./src/index.tsx",
|
||||
"scripts": {
|
||||
|
||||
BIN
src/assets/images/car-body-type/coupe.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/images/car-body-type/crossover.webp
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/assets/images/car-body-type/hatchback.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
10
src/assets/images/car-body-type/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export { default as CoupeImg } from './coupe.webp';
|
||||
export { default as CrossoverImg } from './crossover.webp';
|
||||
export { default as HatchbackImg } from './hatchback.webp';
|
||||
export { default as LiftbackImg } from './liftback.webp';
|
||||
export { default as MinivanImg } from './minivan.webp';
|
||||
export { default as PickupImg } from './pickup.webp';
|
||||
export { default as SedanImg } from './sedan.webp';
|
||||
export { default as SportsCarImg } from './sports-car.webp';
|
||||
export { default as StationWagonImg } from './station-wagon.webp';
|
||||
export { default as SuvImg } from './suv.webp';
|
||||
BIN
src/assets/images/car-body-type/liftback.webp
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/images/car-body-type/minivan.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/images/car-body-type/pickup.webp
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src/assets/images/car-body-type/sedan.webp
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/images/car-body-type/sports-car.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/images/car-body-type/station-wagon.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/images/car-body-type/suv.webp
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
@@ -1 +1,2 @@
|
||||
export * from './car-body-type';
|
||||
export { default as DemoVideoPosterImg } from './demo-video-poster.webp';
|
||||
@@ -1,23 +1,92 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import { Select, SelectProps } from '@chakra-ui/react';
|
||||
import React, { forwardRef, useState } from 'react';
|
||||
import {
|
||||
Input,
|
||||
Image,
|
||||
InputProps,
|
||||
Box,
|
||||
Popover,
|
||||
PopoverAnchor,
|
||||
PopoverContent,
|
||||
PopoverBody,
|
||||
List,
|
||||
ListItem,
|
||||
} from '@chakra-ui/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { carBodySelectOptions } from './helper';
|
||||
import { CarBodySelectOption } from './types';
|
||||
|
||||
export const CarBodySelect = forwardRef<HTMLSelectElement, SelectProps>(
|
||||
export const CarBodySelect = forwardRef<HTMLInputElement, InputProps>(
|
||||
function CarBodySelect(props, ref) {
|
||||
const [selected, setSelected] = useState<Partial<CarBodySelectOption>>({});
|
||||
const handleOptionClick = (option: CarBodySelectOption) => {
|
||||
setSelected(option);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
props.onChange(option.value);
|
||||
};
|
||||
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false);
|
||||
|
||||
const { t } = useTranslation('~', {
|
||||
keyPrefix: 'dry-wash.order-create.car-body-select',
|
||||
});
|
||||
|
||||
return (
|
||||
<Select ref={ref} placeholder={t('placeholder')} {...props}>
|
||||
{carBodySelectOptions.map(({ value, labelTKey }, i) => (
|
||||
<option key={i} value={value}>
|
||||
{t(`options.${labelTKey}`)}
|
||||
</option>
|
||||
<Box width='100%'>
|
||||
<Popover
|
||||
isOpen={isDropdownOpen}
|
||||
autoFocus={false}
|
||||
placement='bottom-start'
|
||||
matchWidth
|
||||
>
|
||||
<PopoverAnchor>
|
||||
<Input
|
||||
{...props}
|
||||
ref={ref}
|
||||
value={
|
||||
selected?.labelTKey
|
||||
? t(`options.${selected.labelTKey}`)
|
||||
: undefined
|
||||
}
|
||||
readOnly
|
||||
onClick={() => setIsDropdownOpen(true)}
|
||||
onBlur={() => setIsDropdownOpen(false)}
|
||||
placeholder={t('placeholder')}
|
||||
/>
|
||||
</PopoverAnchor>
|
||||
<PopoverContent width='100%' maxWidth='100%'>
|
||||
<PopoverBody border='1px' borderColor='gray.300' p={0}>
|
||||
<List
|
||||
display='grid'
|
||||
gridTemplateColumns='repeat(auto-fit, minmax(150px, 1fr))'
|
||||
>
|
||||
{carBodySelectOptions.map((option) => (
|
||||
<ListItem
|
||||
key={option.value}
|
||||
display='flex'
|
||||
flexDirection='column'
|
||||
justifyContent='flex-end'
|
||||
alignItems='center'
|
||||
p={2}
|
||||
cursor='pointer'
|
||||
_hover={{
|
||||
bgColor: 'primary.50',
|
||||
}}
|
||||
_active={{
|
||||
bgColor: 'primary.100',
|
||||
}}
|
||||
onClick={() => handleOptionClick(option)}
|
||||
>
|
||||
<Image src={option.img} />
|
||||
{t(`options.${option.labelTKey}`)}
|
||||
</ListItem>
|
||||
))}
|
||||
</Select>
|
||||
</List>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
import {
|
||||
CoupeImg,
|
||||
CrossoverImg,
|
||||
HatchbackImg,
|
||||
LiftbackImg,
|
||||
MinivanImg,
|
||||
PickupImg,
|
||||
SedanImg,
|
||||
SportsCarImg,
|
||||
StationWagonImg,
|
||||
SuvImg
|
||||
} from "../../../../assets/images";
|
||||
import { Car } from "../../../../models/landing";
|
||||
|
||||
import { CarBodySelectOption } from "./types";
|
||||
@@ -5,43 +17,53 @@ import { CarBodySelectOption } from "./types";
|
||||
export const carBodySelectOptions: CarBodySelectOption[] = [
|
||||
{
|
||||
value: Car.BodyStyle.SEDAN,
|
||||
labelTKey: 'sedan'
|
||||
labelTKey: 'sedan',
|
||||
img: SedanImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.HATCHBACK,
|
||||
labelTKey: 'hatchback'
|
||||
labelTKey: 'hatchback',
|
||||
img: HatchbackImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.CROSSOVER,
|
||||
labelTKey: 'crossover'
|
||||
labelTKey: 'crossover',
|
||||
img: CrossoverImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.SUV,
|
||||
labelTKey: 'suv'
|
||||
labelTKey: 'suv',
|
||||
img: SuvImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.STATION_WAGON,
|
||||
labelTKey: 'station-wagon'
|
||||
labelTKey: 'station-wagon',
|
||||
img: StationWagonImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.COUPE,
|
||||
labelTKey: 'coupe'
|
||||
labelTKey: 'coupe',
|
||||
img: CoupeImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.MINIVAN,
|
||||
labelTKey: 'minivan'
|
||||
labelTKey: 'minivan',
|
||||
img: MinivanImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.PICKUP,
|
||||
labelTKey: 'pickup'
|
||||
labelTKey: 'pickup',
|
||||
img: PickupImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.LIFTBACK,
|
||||
labelTKey: 'liftback'
|
||||
labelTKey: 'liftback',
|
||||
img: LiftbackImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.SPORTS_CAR,
|
||||
labelTKey: 'sports-car'
|
||||
labelTKey: 'sports-car',
|
||||
img: SportsCarImg
|
||||
},
|
||||
{
|
||||
value: Car.BodyStyle.OTHER,
|
||||
|
||||
@@ -14,4 +14,5 @@ export type CarBodySelectOption = {
|
||||
'liftback' |
|
||||
'sports-car' |
|
||||
'other';
|
||||
img?: string;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ export const CarNumberInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
// @ts-ignore
|
||||
onChange?.(formattedValue);
|
||||
}}
|
||||
maxLength={8}
|
||||
maxLength={12}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -3,11 +3,11 @@ const VALID_LETTER = 'а|в|е|к|м|н|о|р|с|т|у|х';
|
||||
const invalidCharsRe = new RegExp(`[^(${VALID_LETTER})0-9]`, 'gi');
|
||||
const cleanValue = (value: string) => value.replace(invalidCharsRe, '');
|
||||
|
||||
const validCarNumberInputRe = new RegExp(`^([${VALID_LETTER}]{1}|$)((?:[0-9]|$)(?:[0-9]|$)(?:[0-9]|$))([${VALID_LETTER}]{1,2}|$)$`, 'gi');
|
||||
const validCarNumberInputRe = new RegExp(`^([${VALID_LETTER}]{1}|$)((?:[0-9]|$)(?:[0-9]|$)(?:[0-9]|$))([${VALID_LETTER}]{1,2}|$)((?:[0-9]|$)(?:[0-9]|$)(?:[0-9]|$))$`, 'gi');
|
||||
const isValidInput = (cleanedValue: string) => validCarNumberInputRe.test(cleanedValue);
|
||||
|
||||
const formatAsCarNumber = (cleanedValue: string) => {
|
||||
return cleanedValue.replace(validCarNumberInputRe, (_, p1, p2, p3) => [p1, p2, p3].join(' ')).toUpperCase();
|
||||
return cleanedValue.replace(validCarNumberInputRe, (_, p1, p2, p3, p4) => [p1, p2, p3, p4].join(' ')).toUpperCase();
|
||||
};
|
||||
const getWithoutLastChar = (value: string) => value.substring(0, value.length - 1);
|
||||
|
||||
@@ -25,7 +25,7 @@ export const handleInputChange = (value: string | undefined | null) => {
|
||||
return getWithoutLastChar(value).trim();
|
||||
};
|
||||
|
||||
const validCarNumberRe = new RegExp(`^[${VALID_LETTER}][0-9]{3}[${VALID_LETTER}]{2}$`, 'i');
|
||||
const validCarNumberRe = new RegExp(`^[${VALID_LETTER}][0-9]{3}[${VALID_LETTER}]{2}[0-9]{2,3}$`, 'i');
|
||||
|
||||
export const isValidCarNumber = (value: string) => {
|
||||
const cleanedValue = cleanValue(value);
|
||||
|
||||