diff --git a/src/declaration.d.ts b/src/declaration.d.ts index 5649f3a..42f3ad4 100644 --- a/src/declaration.d.ts +++ b/src/declaration.d.ts @@ -6,3 +6,8 @@ declare module '*.svg' { >; export default ReactComponent; } + +declare module '*.png' { + const value: string; + export default value; +} diff --git a/src/pages/home/home.page.tsx b/src/pages/home/home.page.tsx index f2e79ac..614c863 100644 --- a/src/pages/home/home.page.tsx +++ b/src/pages/home/home.page.tsx @@ -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 (
-
-
-
+
); }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index d3e8a76..6f9aa3d 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -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: }]; +const routes = [ + { path: '/', element: }, + { path: '/laptop', element: }, + // { path: '/tv', element: }, +]; const Index = () => { return ( diff --git a/src/pages/laptop/index.ts b/src/pages/laptop/index.ts new file mode 100644 index 0000000..09a8e61 --- /dev/null +++ b/src/pages/laptop/index.ts @@ -0,0 +1 @@ +export { default as LaptopPage } from './laptop.page'; diff --git a/src/pages/laptop/laptop.page.tsx b/src/pages/laptop/laptop.page.tsx new file mode 100644 index 0000000..989afed --- /dev/null +++ b/src/pages/laptop/laptop.page.tsx @@ -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({ + processor: '', + ram: 0, + os: '', + ssd: 0, + display_size: 0, + resolution: '', + matrix_type: '', + gpu: '', + }); + + const [response, setResponse] = useState({ + 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 ( +
+ +
+ +
+
+ ); +}; + +export default LaptopPredictPage; diff --git a/src/pages/laptop/styles.module.scss b/src/pages/laptop/styles.module.scss new file mode 100644 index 0000000..46abeb4 --- /dev/null +++ b/src/pages/laptop/styles.module.scss @@ -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); + } +} \ No newline at end of file diff --git a/src/pages/tv/index.ts b/src/pages/tv/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/tv/styles.module.scss b/src/pages/tv/styles.module.scss new file mode 100644 index 0000000..488129d --- /dev/null +++ b/src/pages/tv/styles.module.scss @@ -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); + } +} \ No newline at end of file diff --git a/src/pages/tv/tv.page.tsx b/src/pages/tv/tv.page.tsx new file mode 100644 index 0000000..e8532b5 --- /dev/null +++ b/src/pages/tv/tv.page.tsx @@ -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({ +// display +// }); + +// const [response, setResponse] = useState({ +// 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 ( +//
+// +//
+// +//
+//
+// ); +// }; + +// export default TVPredictPage; diff --git a/src/shared/api/api.laptop.ts b/src/shared/api/api.laptop.ts new file mode 100644 index 0000000..e4acc4d --- /dev/null +++ b/src/shared/api/api.laptop.ts @@ -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 => { + try { + const response = await axios.get( + `${this.baseURL}/get_unique_data_laptop`, + ); + return response.data; + } catch (error) { + console.error('Error predicting price:', error); + throw error; + } + }; + + predictPrice = async ( + data: LaptopCreatePredictType, + ): Promise => { + try { + const response = await axios.post( + `${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; diff --git a/src/shared/api/api.ts b/src/shared/api/api.ts deleted file mode 100644 index d193e6d..0000000 --- a/src/shared/api/api.ts +++ /dev/null @@ -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 => { - try { - const response = await axios.post( - `${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; diff --git a/src/shared/api/api.tv.ts b/src/shared/api/api.tv.ts new file mode 100644 index 0000000..a1753cc --- /dev/null +++ b/src/shared/api/api.tv.ts @@ -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 => { + try { + const response = await axios.get( + `${this.baseURL}/get_unique_data_tv`, + ); + return response.data; + } catch (error) { + console.error('Error predicting price:', error); + throw error; + } + }; + + predictPrice = async ( + data: TVCreatePredictType, + ): Promise => { + try { + const response = await axios.post( + `${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; diff --git a/src/shared/api/index.ts b/src/shared/api/index.ts new file mode 100644 index 0000000..5fe707f --- /dev/null +++ b/src/shared/api/index.ts @@ -0,0 +1,2 @@ +export { default as apiLaptop } from './api.laptop'; +export { default as apiTV } from './api.tv'; diff --git a/src/shared/assets/images/laptop.png b/src/shared/assets/images/laptop.png new file mode 100644 index 0000000..1d75f84 Binary files /dev/null and b/src/shared/assets/images/laptop.png differ diff --git a/src/shared/assets/images/tv.png b/src/shared/assets/images/tv.png new file mode 100644 index 0000000..e827f3f Binary files /dev/null and b/src/shared/assets/images/tv.png differ diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts new file mode 100644 index 0000000..e98fb2c --- /dev/null +++ b/src/shared/types/index.ts @@ -0,0 +1 @@ +export * from './predict'; diff --git a/src/shared/types/predict.ts b/src/shared/types/predict.ts index 17359bc..f5d0283 100644 --- a/src/shared/types/predict.ts +++ b/src/shared/types/predict.ts @@ -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 = { diff --git a/src/widgets/form/form.widget.tsx b/src/widgets/form/form.widget.tsx index 944efe5..b52ed1a 100644 --- a/src/widgets/form/form.widget.tsx +++ b/src/widgets/form/form.widget.tsx @@ -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({ - 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({ - predicted_price: undefined, - }); +type FormType = { + selectorsData: T | undefined; + updateField: (field: keyof T, value: string | number) => void; + handleGetPredict: (e: FormEvent) => Promise; + 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 = >({ + selectorsData, + updateField, + handleGetPredict, + response, +}: FormType) => { + const fields = selectorsData + ? (Object.keys(selectorsData) as Array) + : []; return (
{fields.map((field) => ( - + ))}
- {response.predicted_price && ( + {response.predicted_price !== undefined && ( Ответ: {response.predicted_price}