minimal front

This commit is contained in:
maxnes3 2024-10-30 00:57:52 +04:00
parent 95c0590d67
commit c88bf296a9
10 changed files with 169 additions and 39 deletions

View File

@ -1,9 +1,12 @@
import Form from '@/widgets/form/form.widget';
import classes from './styles.module.scss'; import classes from './styles.module.scss';
const HomePage = () => { const HomePage = () => {
return ( return (
<div className={classes.home}> <div className={classes.home}>
<div className={classes.container}></div> <div className={classes.container}>
<Form />
</div>
</div> </div>
); );
}; };

View File

@ -1,7 +1,17 @@
import React, { FormEvent } from 'react';
import classes from './styles.module.scss'; import classes from './styles.module.scss';
const Button = () => { type ButtonProps = {
return <></>; label: string;
onClick: (e: FormEvent) => Promise<void>;
};
const Button: React.FC<ButtonProps> = ({ label, onClick }) => {
return (
<button className={classes.button} onClick={onClick}>
{label}
</button>
);
}; };
export default Button; export default Button;

View File

@ -1 +1 @@
export { default as Button} from './button.component'; export { default as Button } from './button.component';

View File

@ -0,0 +1,20 @@
.button {
background-color: rgba(255, 255, 255, 0.2); // прозрачный белый фон
border: 2px solid var(--primary-white); // белая обводка
border-radius: 8px; // закруглённые углы
color: var(--primary-white); // белый текст
padding: 10px 20px; // внутренних отступов
font-size: 16px; // размер шрифта
cursor: pointer; // курсор при наведении
transition: background-color 0.3s ease; // плавный переход фона
&:hover {
background-color: rgba(255, 255, 255, 0.4); // изменение цвета фона при наведении
}
&:focus {
outline: none; // убираем стандартный контур при фокусировке
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5); // добавляем тень при фокусировке
}
}

View File

@ -1,18 +1,51 @@
import { FC } from 'react'; import { FC, useState } from 'react';
import classes from './styles.module.scss'; import classes from './styles.module.scss';
type SelectorProps = { type SelectorProps = {
handleSetValue: () => void; field: string;
handleSetValue: (field: string, value: string) => void;
list: string[]; list: string[];
}; };
const Selector: FC<SelectorProps> = ({ handleSetValue, list }) => { const Selector: FC<SelectorProps> = ({ field, handleSetValue, list }) => {
const [inputValue, setInputValue] = useState('');
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
setInputValue(value);
handleSetValue(field, value);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setInputValue(value);
handleSetValue(field, value);
};
return ( return (
<section className={classes.selector}> <div className={classes.selectorContainer}>
{list.map((item) => ( <select
<option>{item}</option> className={classes.selector}
onChange={handleChange}
value={inputValue}
>
<option value="" disabled>
Select an option
</option>
{list.map((item, index) => (
<option key={index} value={item}>
{item}
</option>
))} ))}
</section> </select>
<input
type="text"
className={classes.input}
value={inputValue}
onChange={handleInputChange}
placeholder="Or type your own"
/>
</div>
); );
}; };

View File

@ -0,0 +1,15 @@
.selector {
background-color: rgba(255, 255, 255, 0.2); // прозрачный белый
border: 2px solid var(--primary-white); // белая рамка
border-radius: 8px; // закруглённые углы
color: var(--primary-white); // белый текст
padding: 8px;
font-size: 16px;
cursor: pointer;
option {
background-color: rgba(255, 255, 255, 0.2); // цвет фона для выпадающего списка
color: var(--primary-white); // белый текст в выпадающем списке
}
}

View File

@ -1,7 +1,17 @@
export type PredictRequestType = { export type PredictRequestType = {
brand: string;
} processor: string;
ram: string;
os: string;
ssd: string;
display: number;
gpu: string;
weight: number;
battery_size: number;
release_year: number;
display_type: string;
};
export type PredictResponseType = { export type PredictResponseType = {
predicted_price: number;
} };

View File

@ -3,20 +3,68 @@ import {
PredictRequestType, PredictRequestType,
PredictResponseType, PredictResponseType,
} from '@/shared/types/predict'; } from '@/shared/types/predict';
import { useState } from 'react'; import { FormEvent, useCallback, useState } from 'react';
import classes from './styles.module.scss'; import classes from './styles.module.scss';
import { Button } from '@/shared/components/button';
import { Selector } from '@/shared/components/selector';
const Form = () => { const Form = () => {
const [request, setRequest] = useState<PredictRequestType>({}); const [request, setRequest] = useState<PredictRequestType>({
const [response, setResponse] = useState<PredictResponseType>({}); brand: '',
processor: '',
ram: '',
os: '',
ssd: '',
display: -1,
gpu: '',
weight: -1,
battery_size: -1,
release_year: -1,
display_type: '',
});
const [response, setResponse] = useState<PredictResponseType>({
predicted_price: -1,
});
const handleGetPredict = async () => { const fields = Object.keys(request);
const handleInputChange = useCallback(
(updatedRequest: PredictRequestType) => {
setRequest(updatedRequest);
},
[],
);
const updateField = (field: string, value: string) => {
handleInputChange({
...request,
[field]: value,
});
};
const handleGetPredict = async (event: FormEvent) => {
event.preventDefault();
const newResponse = await api.predictPrice(request); const newResponse = await api.predictPrice(request);
setResponse(newResponse);
}; };
return ( return (
<form> <form className={classes.form}>
<div className={classes.}></div> <div className={classes.selectorList}>
{fields.map((field) => (
<Selector
key={field}
handleSetValue={(value) => updateField(field, value)}
list={[]}
field={field}
/>
))}
</div>
<Button
onClick={(e: FormEvent) => handleGetPredict(e)}
label={'Отправить'}
/>
{response && <span>Ответ: {response.predicted_price}</span>}
</form> </form>
); );
}; };

View File

@ -1,27 +1,18 @@
@use '../../shared/assets/styles/adaptive' as adaptive; @use '../../shared/assets/styles/adaptive' as adaptive;
.navbar { .form {
display: flex; display: flex;
flex-direction: column;
gap: 18px;
background-color: var(--transparent-black); background-color: var(--transparent-black);
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
width: 100%; width: 100%;
justify-content: center; justify-content: center;
padding: 25px;
.container { .selectorList {
padding: 15px;
@include adaptive.container;
.logo {
display: flex; display: flex;
flex-direction: row; flex-direction: column;
justify-content: start;
align-items: end;
gap: 8px; gap: 8px;
color: var(--primary-white);
.title {
margin: 0;
}
}
} }
} }