complete laptop

This commit is contained in:
maxnes3 2024-12-11 04:28:29 +04:00
parent 244aed205b
commit 63a5ecd0e4
18 changed files with 382 additions and 86 deletions

View File

@ -6,3 +6,8 @@ declare module '*.svg' {
>;
export default ReactComponent;
}
declare module '*.png' {
const value: string;
export default value;
}

View File

@ -1,4 +1,3 @@
import Form from '@/widgets/form/form.widget';
import classes from './styles.module.scss';
import Laptop from '@shared/assets/icons/laptop.svg';
@ -6,9 +5,7 @@ const HomePage = () => {
return (
<div className={classes.home}>
<Laptop className={classes.laptop} />
<div className={classes.container}>
<Form />
</div>
<div className={classes.container}></div>
</div>
);
};

View File

@ -1,8 +1,14 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Layout from '@app/layout/layout';
import HomePage from '@pages/home/home.page';
import { LaptopPage } from '@pages/laptop';
// import { TVPage } from '@pages/tv/tv.page';
const routes = [{ path: '/', element: <HomePage /> }];
const routes = [
{ path: '/', element: <HomePage /> },
{ path: '/laptop', element: <LaptopPage /> },
// { path: '/tv', element: <TVPage /> },
];
const Index = () => {
return (

View File

@ -0,0 +1 @@
export { default as LaptopPage } from './laptop.page';

View File

@ -0,0 +1,84 @@
import Form from '@/widgets/form/form.widget';
import classes from './styles.module.scss';
import Laptop from '@shared/assets/images/laptop.png';
import { FormEvent, useCallback, useEffect, useState } from 'react';
import {
LaptopCreatePredictType,
LaptopGetDataPredictType,
PredictResponseType,
} from '@/shared/types';
import { apiLaptop } from '@/shared/api';
const LaptopPredictPage = () => {
const [requestSelectorsData, setRequestSelectorsData] = useState<
LaptopGetDataPredictType | undefined
>();
const [request, setRequest] = useState<LaptopCreatePredictType>({
processor: '',
ram: 0,
os: '',
ssd: 0,
display_size: 0,
resolution: '',
matrix_type: '',
gpu: '',
});
const [response, setResponse] = useState<PredictResponseType>({
predicted_price: undefined,
});
const handleGetPredict = async (event: FormEvent) => {
event.preventDefault();
console.log(request);
const newResponse = await apiLaptop.predictPrice(request);
setResponse(newResponse);
};
const handleInputChange = useCallback(
(updatedRequest: LaptopCreatePredictType) => {
setRequest(updatedRequest);
},
[],
);
const updateField = (
field: keyof LaptopGetDataPredictType,
value: string | number,
) => {
handleInputChange({
...request,
[field]: value,
});
console.log(value);
};
useEffect(() => {
const fetchData = async () => {
const responseSelectorData = await apiLaptop.getDataForRequest();
if (!responseSelectorData) {
return;
}
setRequestSelectorsData(responseSelectorData);
};
fetchData();
}, []);
return (
<div className={classes.laptop}>
<img src={Laptop} className={classes.icon} />
<div className={classes.container}>
<Form
selectorsData={requestSelectorsData}
updateField={updateField}
handleGetPredict={handleGetPredict}
response={response}
/>
</div>
</div>
);
};
export default LaptopPredictPage;

View File

@ -0,0 +1,36 @@
@use '../../shared/assets/styles/adaptive' as adaptive;
$adaptive: (
desktop: (
flex-direction: row,
size: 250px,
container-width: 768px
),
table: (
flex-direction: row,
size: 250px,
container-width: 425px
),
mobile: (
flex-direction: column,
size: auto,
container-width: auto
),
);
.laptop {
display: flex;
justify-content: center;
width: 100%;
@include adaptive.set-adaptive($adaptive, flex-direction, flex-direction);
.icon {
@include adaptive.set-adaptive($adaptive, width, size);
@include adaptive.set-adaptive($adaptive, height, size);
}
.container {
padding: 15px;
@include adaptive.set-adaptive($adaptive, width, container-width);
}
}

0
src/pages/tv/index.ts Normal file
View File

View File

@ -0,0 +1,36 @@
@use '../../shared/assets/styles/adaptive' as adaptive;
$adaptive: (
desktop: (
flex-direction: row,
size: 250px,
container-width: 768px
),
table: (
flex-direction: row,
size: 250px,
container-width: 425px
),
mobile: (
flex-direction: column,
size: auto,
container-width: auto
),
);
.tv {
display: flex;
justify-content: center;
width: 100%;
@include adaptive.set-adaptive($adaptive, flex-direction, flex-direction);
.icon {
@include adaptive.set-adaptive($adaptive, width, size);
@include adaptive.set-adaptive($adaptive, height, size);
}
.container {
padding: 15px;
@include adaptive.set-adaptive($adaptive, width, container-width);
}
}

73
src/pages/tv/tv.page.tsx Normal file
View File

@ -0,0 +1,73 @@
// import Form from '@/widgets/form/form.widget';
// import classes from './styles.module.scss';
// import TV from '@shared/assets/images/tv.png';
// import { FormEvent, useCallback, useEffect, useState } from 'react';
// import {
// TVCreatePredictType,
// TVGetDataPredictType,
// PredictResponseType,
// } from '@/shared/types';
// import { apiTV } from '@/shared/api';
// const TVPredictPage = () => {
// const [requestSelectorsData, setRequestSelectorsData] = useState<
// TVGetDataPredictType | undefined
// >();
// const [request, setRequest] = useState<TVCreatePredictType>({
// display
// });
// const [response, setResponse] = useState<PredictResponseType>({
// predicted_price: undefined,
// });
// const handleGetPredict = async (event: FormEvent) => {
// event.preventDefault();
// console.log(request);
// const newResponse = await apiTV.predictPrice(request);
// setResponse(newResponse);
// };
// const handleInputChange = useCallback(
// (updatedRequest: TVCreatePredictType) => {
// setRequest(updatedRequest);
// },
// [],
// );
// const updateField = (field: string, value: string) => {
// handleInputChange({
// ...request,
// [field]: value,
// });
// };
// useEffect(() => {
// const fetchData = async () => {
// const responseSelectorData = await apiTV.getDataForRequest();
// if (!responseSelectorData) {
// return;
// }
// setRequestSelectorsData(responseSelectorData);
// };
// fetchData();
// }, []);
// return (
// <div className={classes.tv}>
// <img src={TV} className={classes.icon} />
// <div className={classes.container}>
// <Form
// selectorsData={requestSelectorsData}
// updateField={updateField}
// handleGetPredict={handleGetPredict}
// response={response}
// />
// </div>
// </div>
// );
// };
// export default TVPredictPage;

View File

@ -0,0 +1,40 @@
import axios from 'axios';
import {
LaptopGetDataPredictType,
LaptopCreatePredictType,
PredictResponseType,
} from '../types';
class ApiLaptop {
readonly baseURL = import.meta.env.VITE_SERVER_URL;
getDataForRequest = async (): Promise<LaptopGetDataPredictType> => {
try {
const response = await axios.get<LaptopGetDataPredictType>(
`${this.baseURL}/get_unique_data_laptop`,
);
return response.data;
} catch (error) {
console.error('Error predicting price:', error);
throw error;
}
};
predictPrice = async (
data: LaptopCreatePredictType,
): Promise<PredictResponseType> => {
try {
const response = await axios.post<PredictResponseType>(
`${this.baseURL}/predict_price/laptop/`,
data,
);
return response.data;
} catch (error) {
console.error('Error predicting price:', error);
throw error;
}
};
}
const apiLaptop = new ApiLaptop();
export default apiLaptop;

View File

@ -1,24 +0,0 @@
import axios from 'axios';
import { PredictRequestType, PredictResponseType } from '../types/predict';
class Api {
readonly baseURL = import.meta.env.VITE_SERVER_URL;
predictPrice = async (
data: PredictRequestType,
): Promise<PredictResponseType> => {
try {
const response = await axios.post<PredictResponseType>(
`${this.baseURL}/predict_price`,
data,
);
return response.data;
} catch (error) {
console.error('Error predicting price:', error);
throw error;
}
};
}
const api = new Api();
export default api;

40
src/shared/api/api.tv.ts Normal file
View File

@ -0,0 +1,40 @@
import axios from 'axios';
import {
TVCreatePredictType,
TVGetDataPredictType,
PredictResponseType,
} from '../types';
class ApiTV {
readonly baseURL = import.meta.env.VITE_SERVER_URL;
getDataForRequest = async (): Promise<TVGetDataPredictType> => {
try {
const response = await axios.get<TVGetDataPredictType>(
`${this.baseURL}/get_unique_data_tv`,
);
return response.data;
} catch (error) {
console.error('Error predicting price:', error);
throw error;
}
};
predictPrice = async (
data: TVCreatePredictType,
): Promise<PredictResponseType> => {
try {
const response = await axios.post<PredictResponseType>(
`${this.baseURL}/predict_price/tv/`,
data,
);
return response.data;
} catch (error) {
console.error('Error predicting price:', error);
throw error;
}
};
}
const apiTV = new ApiTV();
export default apiTV;

2
src/shared/api/index.ts Normal file
View File

@ -0,0 +1,2 @@
export { default as apiLaptop } from './api.laptop';
export { default as apiTV } from './api.tv';

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1 @@
export * from './predict';

View File

@ -1,15 +1,43 @@
export type PredictRequestType = {
brand: string;
export type LaptopCreatePredictType = {
processor: string;
ram: number;
os: string;
ssd: number;
display: number;
display_size: number;
resolution: string;
matrix_type: string;
gpu: string;
weight: number;
battery_size: number;
release_year: number;
display_type: string;
};
export type LaptopGetDataPredictType = {
processor: string[];
ram: number[];
os: string[];
ssd: number[];
display_size: number[];
resolution: string[];
matrix_type: string[];
gpu: string[];
};
export type TVCreatePredictType = {
display: string;
tuners: string;
features: string;
os: string;
power_of_volume: string;
screen_size: number;
color: string;
};
export type TVGetDataPredictType = {
display: string[];
tuners: string[];
features: string[];
os: string[];
power_of_volume: string[];
screen_size: number[];
color: string[];
};
export type PredictResponseType = {

View File

@ -1,71 +1,42 @@
import api from '@/shared/api/api';
import {
PredictRequestType,
PredictResponseType,
} from '@/shared/types/predict';
import { FormEvent, useCallback, useState } from 'react';
import { PredictResponseType } from '@/shared/types/predict';
import { FormEvent } from 'react';
import classes from './styles.module.scss';
import { Button } from '@/shared/components/button';
import { Selector } from '@/shared/components/selector';
import { mockUpOptions } from '@/shared/constants';
import { Expander } from '@/shared/components/expander';
const Form = () => {
const [request, setRequest] = useState<PredictRequestType>({
brand: 'Apple',
processor: 'Core i5 10th Gen',
ram: 16,
os: 'Windows 11',
ssd: 1024,
display: 15.3,
gpu: 'NVIDIA GeForce RTX 3060',
weight: 2.0,
battery_size: 90,
release_year: 2023,
display_type: '4K',
});
const [response, setResponse] = useState<PredictResponseType>({
predicted_price: undefined,
});
type FormType<T> = {
selectorsData: T | undefined;
updateField: (field: keyof T, value: string | number) => void;
handleGetPredict: (e: FormEvent) => Promise<void>;
response: PredictResponseType;
};
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();
console.log(request);
const newResponse = await api.predictPrice(request);
setResponse(newResponse);
};
const Form = <T extends Record<string, string[] | number[]>>({
selectorsData,
updateField,
handleGetPredict,
response,
}: FormType<T>) => {
const fields = selectorsData
? (Object.keys(selectorsData) as Array<keyof T>)
: [];
return (
<form className={classes.form}>
<div className={classes.selectorList}>
{fields.map((field) => (
<Expander key={field} title={field}>
<Expander key={field as string} title={field as string}>
<Selector
handleSetValue={updateField}
list={mockUpOptions[field]}
field={field}
list={selectorsData ? selectorsData[field] : []}
field={field as string}
/>
</Expander>
))}
</div>
<Button onClick={(e: FormEvent) => handleGetPredict(e)}>Submit</Button>
{response.predicted_price && (
{response.predicted_price !== undefined && (
<span style={{ color: 'white' }}>
Ответ: {response.predicted_price}
</span>