From 4399757fa6003dac8cd3094bda11afab7c429a40 Mon Sep 17 00:00:00 2001 From: VyacheslavShtyrlin Date: Thu, 9 Feb 2023 02:09:19 +0500 Subject: [PATCH] almost done --- src/App.js | 22 ++++ .../AveragePriceApartment.js | 2 +- .../InputComponent/InputComponent.js | 35 +++--- src/components/InputNumber/InputNumber.js | 58 ++++----- src/components/Main/Main.css | 4 +- src/components/Main/Main.js | 34 +++-- src/components/ResultBlock/ResultBlock.css | 85 +++++++++++++ src/components/ResultBlock/ResultBlock.js | 118 ++++++++++++++++++ src/store/reducers/calcSlice.js | 24 ++-- src/store/reducers/calculationSlice.js | 43 +++++++ src/store/store.js | 3 +- 11 files changed, 345 insertions(+), 83 deletions(-) create mode 100644 src/components/ResultBlock/ResultBlock.css create mode 100644 src/components/ResultBlock/ResultBlock.js create mode 100644 src/store/reducers/calculationSlice.js diff --git a/src/App.js b/src/App.js index 6f2bcf8..e8fa565 100644 --- a/src/App.js +++ b/src/App.js @@ -1,8 +1,30 @@ import logo from "./logo.svg"; import { Main } from "./components/Main/Main"; import "./App.css"; +import { useSelector, useDispatch } from "react-redux"; +import { calcSlice } from "./store/reducers/calcSlice"; +import { calculationSlice } from "./store/reducers/calculationSlice"; +import { useEffect } from "react"; function App() { + const state = useSelector((state) => state.calcReducer); + const dispatch = useDispatch(); + const { handleCalculation, handleResultUpdated, handleResultDefault } = calculationSlice.actions; + + useEffect(() => { + dispatch( + handleCalculation({ + squareApartment: state.squareApartment, + priceAvarage: state.priceAvarage, + squareRC: state.squareRC, + consultation: state.consultation, + }) + ); + dispatch(handleResultUpdated()) + dispatch(handleResultDefault()) + + }, [state]); + return (
diff --git a/src/components/AveragePriceApartment/AveragePriceApartment.js b/src/components/AveragePriceApartment/AveragePriceApartment.js index d4455d8..a11c564 100644 --- a/src/components/AveragePriceApartment/AveragePriceApartment.js +++ b/src/components/AveragePriceApartment/AveragePriceApartment.js @@ -5,7 +5,7 @@ export const AveragePriceApartment = () => { const { priceAvarage, total } = useSelector((state) => state.calcReducer); console.log(priceAvarage) - const name = "priceApartment"; + const name = "priceAvarage"; const min = 30000; const max = 200000; const large = true diff --git a/src/components/InputComponent/InputComponent.js b/src/components/InputComponent/InputComponent.js index 681a652..d49c482 100644 --- a/src/components/InputComponent/InputComponent.js +++ b/src/components/InputComponent/InputComponent.js @@ -1,20 +1,26 @@ -import './InputComponent.css' -import edit from './edit.svg' +import "./InputComponent.css"; +import edit from "./edit.svg"; import { useEffect, useState } from "react"; import CurrencyInput from "react-currency-input-field"; import { useDispatch } from "react-redux"; import { calcSlice } from "../../store/reducers/calcSlice"; -export const InputComponent = ({ value, name, min, max, inputClass, large }) => { +export const InputComponent = ({ + value, + name, + min, + max, + inputClass, + large, +}) => { const dispatch = useDispatch(); - const { handleValue, handleTotal } = calcSlice.actions; + const { handleValue } = calcSlice.actions; const [valid, setValid] = useState(false); const [valueInput, setValueInput] = useState(value); - useEffect(() => { - setValueInput(value) - }, [value]) + setValueInput(value); + }, [value]); const handleNumber = (number) => { if (!number) { @@ -25,13 +31,9 @@ export const InputComponent = ({ value, name, min, max, inputClass, large }) => return num; }; - useEffect(() => { - dispatch(handleTotal()); - }, []); - const handleTotalValues = (value, name) => { - dispatch(handleValue({ name: name, value: value })); - dispatch(handleTotal()); + const toNum = parseInt(value) + dispatch(handleValue({ name: name, value: toNum })); }; const handleState = (e) => { @@ -83,7 +85,6 @@ export const InputComponent = ({ value, name, min, max, inputClass, large }) => const handleFocusLeft = (e) => { const { name, value } = e.target; const number = handleNumber(value); - console.log(number, value, "valuie"); if (number === 0 && number === undefined) { handleTotalValues(min, name); return; @@ -116,14 +117,14 @@ export const InputComponent = ({ value, name, min, max, inputClass, large }) => return ( <> -
+
onBlur={(e) => handleFocusLeft(e)} onValueChange={(value, name) => handleOnValueChange(value, name)} /> - edit/изменить + edit/изменить
diff --git a/src/components/InputNumber/InputNumber.js b/src/components/InputNumber/InputNumber.js index 93ee9d2..f7dc546 100644 --- a/src/components/InputNumber/InputNumber.js +++ b/src/components/InputNumber/InputNumber.js @@ -1,37 +1,29 @@ -import './InputNumber.css' -import { useEffect } from 'react'; -import CurrencyInput from 'react-currency-input-field'; -import useFormWithValidation from "../../hooks/useFormWithValidation"; +import "./InputNumber.css"; +import CurrencyInput from "react-currency-input-field"; +import { calcSlice } from "../../store/reducers/calcSlice"; +import { useDispatch } from "react-redux"; -export const InputNumber = ({ number, handleState }) => { +export const InputNumber = ({ number }) => { + const dispatch = useDispatch(); + const { handleValue } = calcSlice.actions; - const { values, handleValidity, resetForm, isTrigger } = - useFormWithValidation(0, 5000); + const onValueChange = (value, name) => { + const toNum = parseInt(value) + dispatch(handleValue({ name: name, value: toNum })); + }; - useEffect(() => { - if (isTrigger) { - handleState(prevState => ({ ...prevState, rcNumber: parseInt(values) })) - - } - }, [values]) - - - useEffect(() => { - handleValidity(number) - }, []) - - - return (
- - Кв. м жилья в жилом комплексе - - handleValidity(value)} - className="input-number" - name='squareRC' - decimalSeparator=' ' - /> + return ( +
+ + Кв. м жилья в жилом комплексе + + onValueChange(value, name)} + className="input-number" + name="squareRC" + decimalSeparator=" " + />
- ) -} \ No newline at end of file + ); +}; diff --git a/src/components/Main/Main.css b/src/components/Main/Main.css index 9e2cf3d..03c96c1 100644 --- a/src/components/Main/Main.css +++ b/src/components/Main/Main.css @@ -14,7 +14,7 @@ width: 68%; background: #1C1D22; border-radius: 4px; - padding: 56px; + padding: 40px; box-sizing: border-box; @@ -27,7 +27,7 @@ gap: 32px; max-width: 1440px; margin: 0 auto; - padding-top: 74px; + padding: 40px; } .map-main-component { diff --git a/src/components/Main/Main.js b/src/components/Main/Main.js index 905548d..9f00313 100644 --- a/src/components/Main/Main.js +++ b/src/components/Main/Main.js @@ -3,35 +3,33 @@ import { useEffect } from "react"; import { calcSlice } from "../../store/reducers/calcSlice"; import { useSelector, useDispatch } from "react-redux"; - import { InputSelect } from "../InputSelect/InputSelect"; import { InputNumber } from "../InputNumber/InputNumber"; -import { AveragePriceApartment } from '../AveragePriceApartment/AveragePriceApartment'; -import { AverageSquareApartment } from '../AverageSquareApartment/AverageSquareApartment' +import { AveragePriceApartment } from "../AveragePriceApartment/AveragePriceApartment"; +import { AverageSquareApartment } from "../AverageSquareApartment/AverageSquareApartment"; import { ConsultationOffice } from "../ConsultationOffice/ConsultationOffice"; import { ConsultationReserv } from "../ConsultationReserv/ConsultationReserv"; import { Sales } from "../Sales/Sales"; +import { ResultBlock } from "../ResultBlock/ResultBlock"; const INITIAL_REGION = "e5b7edfb-17ec-475f-8631-bc796ad19909"; -export const Main = ({ }) => { - - const dispatch = useDispatch() - const { handleSelectRegion, handleOptions, handleValue } = calcSlice.actions - const { selectedRegion, options, squareRC } = useSelector((state) => state.calcReducer); - +export const Main = ({}) => { + const dispatch = useDispatch(); + const { handleSelectRegion, handleOptions, handleValue } = calcSlice.actions; + const { selectedRegion, options, squareRC } = useSelector( + (state) => state.calcReducer + ); useEffect(() => { - dispatch(handleSelectRegion(INITIAL_REGION)) - dispatch(handleOptions()) - }, []) - + dispatch(handleSelectRegion(INITIAL_REGION)); + dispatch(handleOptions()); + }, []); const handleSelect = (element) => { - dispatch(handleSelectRegion(element.id)) + dispatch(handleSelectRegion(element.id)); }; - return (
@@ -45,12 +43,10 @@ export const Main = ({ }) => {
- + -
-
- +
); diff --git a/src/components/ResultBlock/ResultBlock.css b/src/components/ResultBlock/ResultBlock.css new file mode 100644 index 0000000..1ef5096 --- /dev/null +++ b/src/components/ResultBlock/ResultBlock.css @@ -0,0 +1,85 @@ +.result-container { + display: flex; + flex-direction: column; + gap: 10px; +} + +.rub-container { +} + +.numbers-container { + display: flex; + align-items: flex-end; + gap: 16px; +} + +.result-block { + display: flex; + flex-direction: row; + gap: 46px; +} + +.result-number { + font-style: normal; + font-weight: 400; + font-size: 54px; + line-height: 100%; + /* identical to box height, or 58px */ + margin: 0; + color: #219653; +} + +.result-caption { + + font-style: normal; + font-weight: 500; + font-size: 22px; + line-height: 120%; + /* identical to box height, or 29px */ + margin: 0; + color: #219653; +} + +.result-number_one { + font-style: normal; + font-weight: 400; + font-size: 24px; + line-height: 100%; + /* identical to box height, or 24px */ + + /* Gray/Accent */ + + color: #393c46; +} + +.result-caption_one { + font-style: normal; + font-weight: 500; + font-size: 10px; + line-height: 120%; + /* identical to box height, or 12px */ + + /* Gray/Accent */ + + color: #393c46; +} + +.result-diff-caption { + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 140%; + /* or 20px */ + + /* White */ + + color: #f7f7f7; +} + +.diff { + color: #d375ff; +} + +.padding { + padding-bottom: 6px; +} \ No newline at end of file diff --git a/src/components/ResultBlock/ResultBlock.js b/src/components/ResultBlock/ResultBlock.js new file mode 100644 index 0000000..240dc10 --- /dev/null +++ b/src/components/ResultBlock/ResultBlock.js @@ -0,0 +1,118 @@ +import "./ResultBlock.css"; +import { useSelector } from "react-redux"; + +export const ResultBlock = () => { + const { timeUpdated, timeDefalut, priceDefault, priceUpdated } = useSelector( + (state) => state.calculationReducer + ); + + const handleMouthPostifx = (num) => { + num = num % 100; + + if (num > 19) { + num = num % 10; + } + + switch (num) { + case 1: + return 0; + + case 2: + case 3: + case 4: + return 1; + + default: + return 2; + } + }; + + const handleMounth = (num, type) => { + const monthesPostfixes = [" месяц", " месяца", " месяцев"]; + + let postfix = handleMouthPostifx(num); + let value1 = monthesPostfixes[postfix]; + + return handleNode(num, value1, type); + }; + + const shortenNumRu = (num, type) => { + if (isNaN(num)) throw new Error(num + " is not a Number!"); + let currency = { + 0: "", + 1: " тыс. руб.", + 2: " млн. руб", + 3: " млрд. руб", + }; + let thousands = Math.floor((("" + num).length - 1) / 3); + let coef = 1000 ** thousands; + + console.log(thousands, "COEF"); + + let value = (num / coef).toFixed(1); + let value1 = currency[thousands]; + + return handleNode(value, value1, type); + }; + + const handleNode = (value, value1, type) => { + if (type === 1) { + return ( + <> + {value} + {value1} + + ); + } else if (type === 0) { + return ( + <> + {value} + {value1} + + ); + } else if (type === 3) { + return ( + + На {`${value} ${value1}`} вы сократили + срок реализации проекта + + ); + } else { + return ( + + На {`${value} ${value1}`} в месяц вы + заработали больше с помощью нашего инструмента продаж + + ); + } + }; + + return ( +
+
+
+
+ {handleMounth(Math.round(timeDefalut), 1)} +
+
+ {handleMounth(Math.round(timeUpdated), 0)} +
+
+
+ {handleMounth(Math.round(timeDefalut) - Math.round(timeUpdated), 3)} +
+
+
+
+
+ {shortenNumRu(Math.round(priceUpdated), 1)} +
+
+ {shortenNumRu(Math.round(priceDefault), 0)} +
+
+
{shortenNumRu(Math.floor(priceUpdated - priceDefault), 4)}
+
+
+ ); +}; diff --git a/src/store/reducers/calcSlice.js b/src/store/reducers/calcSlice.js index ea03464..8cc1da9 100644 --- a/src/store/reducers/calcSlice.js +++ b/src/store/reducers/calcSlice.js @@ -3,15 +3,16 @@ import { regions } from "../../utils/array"; const initialState = { squareRC: 1500, - squareApartment: 100, + squareApartment: 45, priceAvarage: 100000, consultation: 100, consultationReserv: 30, sales: 10, - total: null, + averagePriceApartment: null, regions: regions, selectedRegion: {}, - options: [] + options: [], + averageNumberApartment: null, }; export const calcSlice = createSlice({ @@ -20,16 +21,18 @@ export const calcSlice = createSlice({ reducers: { handleOptions(state) { const options = state.regions.filter((i) => i.name); - return { ...state, options: options } - + return { ...state, options: options }; }, handleSelectRegion(state, action) { - console.log(action) const region = state.regions.find((i) => i.id === action.payload); - return { ...state, selectedRegion: region, priceAvarage: region.price } + return { + ...state, + selectedRegion: region, + priceAvarage: parseInt(region.price), + }; }, handleValue(state, action) { - console.log(action.payload.value) + console.log(action.payload.value, "ss"); return { ...state, [action.payload.name]: action.payload.value }; }, handleInitalState(state, action) { @@ -39,8 +42,9 @@ export const calcSlice = createSlice({ }; }, handleTotal(state) { - const number = Number(state.squareApartment) - state.total = number + 20; + console.log(state.priceAvarage, "price"); + state.averagePriceApartment = state.squareApartment * state.priceAvarage; + state.averageNumberApartment = state.squareRC / state.squareApartment; }, }, }); diff --git a/src/store/reducers/calculationSlice.js b/src/store/reducers/calculationSlice.js new file mode 100644 index 0000000..77c8dd1 --- /dev/null +++ b/src/store/reducers/calculationSlice.js @@ -0,0 +1,43 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + averageNumberApartment: 0, + averagePriceApartment: 0, + priceDefault: 0, + priceUpdated: 0, + timeDefalut: 0, + timeUpdated: 0, + consultationNumber: 0, +}; + +export const calculationSlice = createSlice({ + name: "calculation", + initialState, + reducers: { + handleCalculation(state, action) { + state.averagePriceApartment = + action.payload.squareApartment * action.payload.priceAvarage; + state.averageNumberApartment = + action.payload.squareRC / action.payload.squareApartment; + state.consultationNumber = action.payload.consultation; + console.log(action.payload); + }, + handleResultDefault(state) { + + const reserved = (state.consultationNumber / 100) * 30; + const sales = (reserved / 100) * 10; + state.timeDefalut = state.averageNumberApartment / sales; + state.priceDefault = sales * state.averagePriceApartment; + console.log(state.averageNumberApartment, sales, 'reducer') + }, + + handleResultUpdated(state) { + const reserved = (state.consultationNumber / 100) * 45; + const sales = (reserved / 100) * 20; + state.timeUpdated = state.averageNumberApartment / sales; + state.priceUpdated = sales * state.averagePriceApartment; + }, + }, +}); + +export default calculationSlice.reducer; diff --git a/src/store/store.js b/src/store/store.js index 2cc8bbf..68d49a7 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -1,7 +1,8 @@ import { combineReducers, configureStore } from "@reduxjs/toolkit"; import calcReducer from "./reducers/calcSlice"; +import calculationReducer from './reducers/calculationSlice' -const rootReducer = combineReducers({ calcReducer }); +const rootReducer = combineReducers({ calcReducer, calculationReducer}); export const setupStore = () => { return configureStore({