Compare commits

...

6 Commits

Author SHA1 Message Date
e8634c396f 0.4.0
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
2025-01-12 10:15:20 +03:00
edddf6d857 Merge pull request 'feat: add image to car body style select option (#55)' (#61) from feature/graphic-car-body-select into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #61
Reviewed-by: Primakov Alexandr Alexandrovich <primakovpro@gmail.com>
2025-01-12 10:13:19 +03:00
1276b13fec Merge pull request 'feat: add fetch for multi-stub (#59)' (#60) from feature/arm-masters-back into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #60
2025-01-12 10:13:04 +03:00
2aa361e3db Merge pull request 'feat: add region code to car number (#54)' (#58) from feature/car-number-region-code into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #58
Reviewed-by: Primakov Alexandr Alexandrovich <primakovpro@gmail.com>
2025-01-12 10:12:42 +03:00
RustamRu
4cda998bd7 feat: add image to car body style select option (#55)
All checks were successful
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
it-academy/dry-wash-pl/pipeline/head This commit looks good
2025-01-12 09:05:36 +03:00
RustamRu
3e0e570ff6 feat: add region code to car number (#54)
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
2025-01-11 18:27:12 +03:00
19 changed files with 130 additions and 27 deletions

4
package-lock.json generated
View File

@@ -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",

View File

@@ -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": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View 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';

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1 +1,2 @@
export * from './car-body-type';
export { default as DemoVideoPosterImg } from './demo-video-poster.webp';

View File

@@ -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>
))}
</Select>
<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>
))}
</List>
</PopoverBody>
</PopoverContent>
</Popover>
</Box>
);
},
);

View File

@@ -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,

View File

@@ -14,4 +14,5 @@ export type CarBodySelectOption = {
'liftback' |
'sports-car' |
'other';
img?: string;
};

View File

@@ -15,7 +15,7 @@ export const CarNumberInput = forwardRef<HTMLInputElement, InputProps>(
// @ts-ignore
onChange?.(formattedValue);
}}
maxLength={8}
maxLength={12}
/>
);
},

View File

@@ -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);