added search and animation result

This commit is contained in:
VyacheslavShtyrlin
2023-02-10 10:06:13 +05:00
parent 4399757fa6
commit 25c4aadce3
18 changed files with 720 additions and 177 deletions
+185
View File
@@ -12,6 +12,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"framer-motion": "^9.0.2",
"nouislider-react": "^3.4.1",
"rc-slider": "^10.1.0",
"react": "^18.2.0",
@@ -2139,6 +2140,21 @@
"postcss-selector-parser": "^6.0.10"
}
},
"node_modules/@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"dependencies": {
"@emotion/memoize": "0.7.4"
}
},
"node_modules/@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"node_modules/@eslint/eslintrc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
@@ -2983,6 +2999,64 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
"node_modules/@motionone/animation": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
"integrity": "sha512-mZcJxLjHor+bhcPuIFErMDNyrdb2vJur8lSfMCsuCB4UyV8ILZLvK+t+pg56erv8ud9xQGK/1OGPt10agPrCyQ==",
"dependencies": {
"@motionone/easing": "^10.15.1",
"@motionone/types": "^10.15.1",
"@motionone/utils": "^10.15.1",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/dom": {
"version": "10.15.5",
"resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.15.5.tgz",
"integrity": "sha512-Xc5avlgyh3xukU9tydh9+8mB8+2zAq+WlLsC3eEIp7Ax7DnXgY7Bj/iv0a4X2R9z9ZFZiaXK3BO0xMYHKbAAdA==",
"dependencies": {
"@motionone/animation": "^10.15.1",
"@motionone/generators": "^10.15.1",
"@motionone/types": "^10.15.1",
"@motionone/utils": "^10.15.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/easing": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.15.1.tgz",
"integrity": "sha512-6hIHBSV+ZVehf9dcKZLT7p5PEKHGhDwky2k8RKkmOvUoYP3S+dXsKupyZpqx5apjd9f+php4vXk4LuS+ADsrWw==",
"dependencies": {
"@motionone/utils": "^10.15.1",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/generators": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.15.1.tgz",
"integrity": "sha512-67HLsvHJbw6cIbLA/o+gsm7h+6D4Sn7AUrB/GPxvujse1cGZ38F5H7DzoH7PhX+sjvtDnt2IhFYF2Zp1QTMKWQ==",
"dependencies": {
"@motionone/types": "^10.15.1",
"@motionone/utils": "^10.15.1",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/types": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.15.1.tgz",
"integrity": "sha512-iIUd/EgUsRZGrvW0jqdst8st7zKTzS9EsKkP+6c6n4MPZoQHwiHuVtTQLD6Kp0bsBLhNzKIBlHXponn/SDT4hA=="
},
"node_modules/@motionone/utils": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.15.1.tgz",
"integrity": "sha512-p0YncgU+iklvYr/Dq4NobTRdAPv9PveRDUXabPEeOjBLSO/1FNB2phNTZxOxpi1/GZwYpAoECEa0Wam+nsmhSw==",
"dependencies": {
"@motionone/types": "^10.15.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -8262,6 +8336,23 @@
"url": "https://www.patreon.com/infusion"
}
},
"node_modules/framer-motion": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-9.0.2.tgz",
"integrity": "sha512-n7ZdIUBrT1xklowQNRQ6/h54+3ysmz422CP0rrhjE1X2tshiJy0WWQ7tv6y/fcOSQd23htNA9vvbUFLYMQ5lEQ==",
"dependencies": {
"@motionone/dom": "^10.15.3",
"hey-listen": "^1.0.8",
"tslib": "^2.4.0"
},
"optionalDependencies": {
"@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -8617,6 +8708,11 @@
"he": "bin/he"
}
},
"node_modules/hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
},
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -18628,6 +18724,21 @@
"integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==",
"requires": {}
},
"@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"requires": {
"@emotion/memoize": "0.7.4"
}
},
"@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"@eslint/eslintrc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
@@ -19253,6 +19364,64 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
"@motionone/animation": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
"integrity": "sha512-mZcJxLjHor+bhcPuIFErMDNyrdb2vJur8lSfMCsuCB4UyV8ILZLvK+t+pg56erv8ud9xQGK/1OGPt10agPrCyQ==",
"requires": {
"@motionone/easing": "^10.15.1",
"@motionone/types": "^10.15.1",
"@motionone/utils": "^10.15.1",
"tslib": "^2.3.1"
}
},
"@motionone/dom": {
"version": "10.15.5",
"resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.15.5.tgz",
"integrity": "sha512-Xc5avlgyh3xukU9tydh9+8mB8+2zAq+WlLsC3eEIp7Ax7DnXgY7Bj/iv0a4X2R9z9ZFZiaXK3BO0xMYHKbAAdA==",
"requires": {
"@motionone/animation": "^10.15.1",
"@motionone/generators": "^10.15.1",
"@motionone/types": "^10.15.1",
"@motionone/utils": "^10.15.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"@motionone/easing": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.15.1.tgz",
"integrity": "sha512-6hIHBSV+ZVehf9dcKZLT7p5PEKHGhDwky2k8RKkmOvUoYP3S+dXsKupyZpqx5apjd9f+php4vXk4LuS+ADsrWw==",
"requires": {
"@motionone/utils": "^10.15.1",
"tslib": "^2.3.1"
}
},
"@motionone/generators": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.15.1.tgz",
"integrity": "sha512-67HLsvHJbw6cIbLA/o+gsm7h+6D4Sn7AUrB/GPxvujse1cGZ38F5H7DzoH7PhX+sjvtDnt2IhFYF2Zp1QTMKWQ==",
"requires": {
"@motionone/types": "^10.15.1",
"@motionone/utils": "^10.15.1",
"tslib": "^2.3.1"
}
},
"@motionone/types": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.15.1.tgz",
"integrity": "sha512-iIUd/EgUsRZGrvW0jqdst8st7zKTzS9EsKkP+6c6n4MPZoQHwiHuVtTQLD6Kp0bsBLhNzKIBlHXponn/SDT4hA=="
},
"@motionone/utils": {
"version": "10.15.1",
"resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.15.1.tgz",
"integrity": "sha512-p0YncgU+iklvYr/Dq4NobTRdAPv9PveRDUXabPEeOjBLSO/1FNB2phNTZxOxpi1/GZwYpAoECEa0Wam+nsmhSw==",
"requires": {
"@motionone/types": "^10.15.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -23146,6 +23315,17 @@
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA=="
},
"framer-motion": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-9.0.2.tgz",
"integrity": "sha512-n7ZdIUBrT1xklowQNRQ6/h54+3ysmz422CP0rrhjE1X2tshiJy0WWQ7tv6y/fcOSQd23htNA9vvbUFLYMQ5lEQ==",
"requires": {
"@emotion/is-prop-valid": "^0.8.2",
"@motionone/dom": "^10.15.3",
"hey-listen": "^1.0.8",
"tslib": "^2.4.0"
}
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -23394,6 +23574,11 @@
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
},
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+1
View File
@@ -7,6 +7,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"framer-motion": "^9.0.2",
"nouislider-react": "^3.4.1",
"rc-slider": "^10.1.0",
"react": "^18.2.0",
+1 -1
View File
@@ -35,4 +35,4 @@
to {
transform: rotate(360deg);
}
}
}
@@ -3,7 +3,6 @@
flex-direction: column;
gap: 17px;
width: 100%;
}
.caption-input {
@@ -16,7 +15,7 @@
/* Landing/Blue/Default */
color: #567ECE;
color: #567ece;
}
.caption-input_type_two {
@@ -29,17 +28,15 @@
/* Landing/Blue/Default */
color: #2B5EC6;
color: #2b5ec6;
}
.input_type_one {
-webkit-appearance: none;
background: #888888;
height: 2px;
cursor: pointer;
background-image: linear-gradient(#567ECE, #567ECE);
background-image: linear-gradient(#567ece, #567ece);
background-size: 70% 100%;
background-repeat: no-repeat;
}
@@ -50,7 +47,7 @@
border-radius: 2px;
height: 28px;
cursor: pointer;
background-image: linear-gradient(#2B5EC6, #2B5EC6);
background-image: linear-gradient(#2b5ec6, #2b5ec6);
background-size: 70% 100%;
background-repeat: no-repeat;
}
@@ -64,12 +61,12 @@
.input_type_two::-webkit-slider-thumb {
-webkit-appearance: none;
background: #F7F7F7;
background: #f7f7f7;
/* Button/Blue/Default */
width: 8px;
height: 16px;
border: 1.2px solid #2B5EC6;
border: 1.2px solid #2b5ec6;
border-radius: 1.2px;
}
@@ -80,17 +77,14 @@
background: transparent;
}
.input_type_one::-webkit-slider-thumb {
-webkit-appearance: none;
background: #567ECE;
background: #567ece;
height: 15px;
width: 15px;
border-radius: 50%;
}
.input-container {
flex-direction: column;
display: flex;
@@ -108,13 +102,12 @@
/* Landing/Blue/Default */
color: #567ECE;
color: #567ece;
display: flex;
margin-top: 12px;
justify-content: space-between;
}
.value-container_type_two {
font-family: "Inter";
font-style: normal;
@@ -126,12 +119,12 @@
text-align: center;
/* Landing/Blue/Default */
color: #2B5EC6;
color: #2b5ec6;
display: flex;
margin-top: 12px;
justify-content: space-between;
}
}
.number-input {
-webkit-appearance: none;
@@ -145,12 +138,15 @@
font-size: 21.6px;
line-height: 135%;
/* or 29px */
/* White */
box-sizing: border-box;
background-color: transparent;
color: #f7f7f7;
}
.number-input:focus {
background: rgba(86, 126, 206, 0.1);
}
.number-container {
display: flex;
align-items: center;
@@ -158,4 +154,4 @@
.edit-icon {
cursor: pointer;
}
}
@@ -1,6 +1,6 @@
import "./InputComponent.css";
import edit from "./edit.svg";
import { useEffect, useState } from "react";
import { useEffect, useState, useRef } from "react";
import CurrencyInput from "react-currency-input-field";
import { useDispatch } from "react-redux";
import { calcSlice } from "../../store/reducers/calcSlice";
@@ -17,7 +17,9 @@ export const InputComponent = ({
const { handleValue } = calcSlice.actions;
const [valid, setValid] = useState(false);
const [valueInput, setValueInput] = useState(value);
const [disabled, setDisabled] = useState(false);
const inputRef = useRef();
useEffect(() => {
setValueInput(value);
}, [value]);
@@ -27,12 +29,11 @@ export const InputComponent = ({
return;
}
const num = Number(number.replace(/ /g, ""));
console.log(num, "test");
return num;
};
const handleTotalValues = (value, name) => {
const toNum = parseInt(value)
const toNum = parseInt(value);
dispatch(handleValue({ name: name, value: toNum }));
};
@@ -83,6 +84,7 @@ export const InputComponent = ({
};
const handleFocusLeft = (e) => {
setDisabled(false);
const { name, value } = e.target;
const number = handleNumber(value);
if (number === 0 && number === undefined) {
@@ -115,10 +117,19 @@ export const InputComponent = ({
return width;
};
const handleFocus = () => {
setDisabled(true);
setTimeout(() => {
inputRef.current.focus();
}, 100);
};
return (
<>
<div className="number-container">
<CurrencyInput
ref={inputRef}
disabled={!disabled}
className="number-input"
decimalsLimit={3}
allowNegativeValue={false}
@@ -132,7 +143,12 @@ export const InputComponent = ({
onBlur={(e) => handleFocusLeft(e)}
onValueChange={(value, name) => handleOnValueChange(value, name)}
/>
<img className="edit-icon" alt="edit/изменить" src={edit} />
<img
onClick={handleFocus}
className="edit-icon"
alt="edit/изменить"
src={edit}
/>
</div>
<div className="input-container">
+82 -4
View File
@@ -2,24 +2,102 @@ import "./InputNumber.css";
import CurrencyInput from "react-currency-input-field";
import { calcSlice } from "../../store/reducers/calcSlice";
import { useDispatch } from "react-redux";
import { useState } from "react";
export const InputNumber = ({ number }) => {
const [valid, setValid] = useState(false);
const [valueInput, setValueInput] = useState(number);
const min = 0;
const max = 10000000;
const dispatch = useDispatch();
const { handleValue } = calcSlice.actions;
const onValueChange = (value, name) => {
const toNum = parseInt(value)
const handleTotalValues = (value, name) => {
const toNum = parseInt(value);
dispatch(handleValue({ name: name, value: toNum }));
};
const handleValidity = (number) => {
if (!(number < max && number > min && number !== 0)) {
setValid(false);
return false;
} else {
setValid(true);
return true;
}
};
const handleNumber = (number) => {
if (!number) {
return;
}
const num = Number(number.replace(/ /g, ""));
return num;
};
const handleOnValueChange = (value, name) => {
const number = handleNumber(value);
setValueInput(number);
setValid(false);
if (!name) {
return;
}
if (!value) {
setValueInput("");
return;
}
if (!Number.isNaN(number)) {
const validity = handleValidity(number);
if (validity) {
handleTotalValues(number, name);
return;
} else {
return;
}
}
};
const handleFocusLeft = (e) => {
const { name, value } = e.target;
const number = handleNumber(value);
if (number === 0 && number === undefined && number === '') {
handleTotalValues(min, name);
return;
} else {
if (!valid) {
if (!(number < max)) {
handleTotalValues(max, name);
setValueInput(max);
return;
}
if (number <= min) {
handleTotalValues(min, name);
setValueInput(min);
return;
}
} else {
return;
}
}
};
return (
<div>
<span className="input-number-caption">
Кв. м жилья в жилом комплексе
</span>
<CurrencyInput
value={number}
onValueChange={(value, name) => onValueChange(value, name)}
onBlur={(e) => handleFocusLeft(e)}
value={valueInput}
onValueChange={(value, name) => handleOnValueChange(value, name)}
className="input-number"
name="squareRC"
decimalSeparator=" "
+3
View File
@@ -0,0 +1,3 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.1667 10.5004L14 18.667L5.83337 10.5004" stroke="#F7F7F7" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 241 B

+33 -9
View File
@@ -13,9 +13,8 @@
/* identical to box height, or 24px */
cursor: pointer;
font-family: "GilroyWebRegular";
/* Landing/White */
width: 100%;
border: none;
color: #ebebeb;
position: relative;
height: 52px;
@@ -24,6 +23,18 @@
border-radius: 8px;
}
.select:focus {
outline: none;
}
.icon-select {
position: absolute;
right: 20px;
top: 13px;
width: 28px;
height: 28px;
}
.select-container {
height: 321px;
}
@@ -65,15 +76,30 @@
.option-container {
z-index: 99;
height: auto;
background: #141414;
position: absolute;
width: 100%;
height: 256px;
max-height: 256px;
overflow: hidden;
overflow-y: scroll;
}
.option-container::-webkit-scrollbar-track {
background: #393c46;
border-radius: 7px;
}
.option-container::-webkit-scrollbar {
width: 4px;
}
.option-container::-webkit-scrollbar-thumb {
background: #2b5ec6;
border-radius: 8px;
height: 38px;
}
.option:hover {
opacity: 0.8;
}
@@ -117,17 +143,15 @@
display: flex;
align-items: center;
justify-content: center;
}
.map-caption {
font-style: normal;
font-weight: 500;
font-size: 12px;
line-height: 130%;
/* or 16px */
margin-bottom: 30px;
margin-top: 5px;
margin-bottom: 10px;
/* Landing/LightGray */
color: #888888;
+76 -50
View File
@@ -1,76 +1,102 @@
import { useState, useEffect, useRef } from "react";
import { calcSlice } from "../../store/reducers/calcSlice";
import { useDispatch } from "react-redux";
import icon from "./Chevron.svg";
import { motion } from "framer-motion";
import { MapComponent } from "../MapComponent/MapComponent";
import "./InputSelect.css";
export const InputSelect = ({
handleSelect,
selectedValue,
option,
}) => {
const selectInput = useRef()
const divInput = useRef()
export const InputSelect = ({ handleSelect, selectedValue, option }) => {
const dispatch = useDispatch();
const { handleSearch, handleOptions } = calcSlice.actions;
const divInput = useRef();
const [show, setShow] = useState(false);
const [text, setText] = useState("");
const transition = { duration: 0.3, ease: "easeOut" };
console.log(option, 'pt')
const iconAnimation = {
open: {
transform: "rotate(180deg)",
},
closed: { transform: "rotate(0deg)" },
};
const handleSelectRegion = (i) => {
handleSelect(i)
handleSelect(i);
closeDropDown();
}
};
const closeDropDown = () => {
setShow(false)
}
setShow(false);
};
const handleShow = ({ }) => {
const handleShow = ({}) => {
if (!show) {
setTimeout(() => {
selectInput.current.focus()
}, 200)
setShow(true)
setShow(true);
} else {
closeDropDown()
closeDropDown();
setText("");
}
}
};
const onSearch = (e) => {
setText(e.target.value);
dispatch(handleSearch({ query: e.target.value }));
};
useEffect(() => {
const handleClose = (e) => {
dispatch(handleOptions());
setText("");
if (e.target !== divInput.current) {
closeDropDown();
}
}
document.addEventListener('click', handleClose)
};
document.addEventListener("click", handleClose);
return () => {
document.removeEventListener('click', handleClose);
}
}, [])
document.removeEventListener("click", handleClose);
};
}, []);
console.log(show, "showDis ");
return (
<div className="">
<div className="select-container">
<div ref={divInput} onClick={handleShow} className="select">{selectedValue.name}
</div>
<div
className="container">
{show && (<>
<div
className="option-container">
{option.map((i) => (
<button
onClick={() => handleSelectRegion(i)}
key={i.id}
value={i.price}
className="option"
>
<p className="option-name"> {i.name}</p>
</button>
))}
</div>
</>
<div style={{ position: "relative" }} className="">
<motion.img
transition={transition}
variants={iconAnimation}
animate={show ? "open" : "closed"}
className="icon-select"
src={icon}
></motion.img>
<div onClick={handleShow} className="select-container">
<input
ref={divInput}
type="text"
onChange={(e) => onSearch(e)}
value={show ? text : selectedValue.name}
placeholder={!show ? "" : selectedValue.name}
className="select"
></input>
<div className="container">
{show && (
<>
<div className="option-container">
{option.map((i) => (
<button
onClick={() => handleSelectRegion(i)}
key={i.id}
value={i.price}
className="option"
>
<p className="option-name"> {i.name}</p>
</button>
))}
</div>
</>
)}
<div
className="map-input">
<div className="map-input">
<MapComponent
handleSelect={handleSelect}
selectedValue={selectedValue}
@@ -78,10 +104,10 @@ export const InputSelect = ({
</div>
</div>
</div>
<span className="map-caption">
<div className="map-caption">
Данные будут установлены в соответсвии со средними показателями по
выбранному региону.
</span>
</div>
</div>
);
};
+9 -5
View File
@@ -4,7 +4,7 @@
border-radius: 16px;
display: flex;
flex-direction: column;
gap: 30px;
gap: 48px;
}
.input-container-second {
@@ -12,12 +12,10 @@
flex-direction: column;
gap: 33px;
width: 68%;
background: #1C1D22;
background: #1c1d22;
border-radius: 4px;
padding: 40px;
box-sizing: border-box;
}
.main {
@@ -28,10 +26,16 @@
max-width: 1440px;
margin: 0 auto;
padding: 40px;
user-select: none;
}
.map-main-component {
background: #0e0e0e;
position: absolute;
z-index: 99;
}
}
svg {
width: 100%;
height: 235px;
}
+2 -2
View File
@@ -17,7 +17,7 @@ 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(
const { selectedRegion, filteredList, squareRC } = useSelector(
(state) => state.calcReducer
);
@@ -34,7 +34,7 @@ export const Main = ({}) => {
<div className="main">
<div className="input-container-main">
<InputSelect
option={options}
option={filteredList}
handleSelect={handleSelect}
selectedValue={selectedRegion}
></InputSelect>
+1 -1
View File
@@ -62,7 +62,7 @@
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 60px;
margin-bottom: 30px;
}
+22 -3
View File
@@ -43,7 +43,7 @@ export const MapComponent = ({
fillRule="evenodd"
clipRule="evenodd"
d={borders.d}
fill={borders.fill}
fill="url(#paint0_linear_235_220192)"
></path>
{regions.map((i) => (
<Region
@@ -56,12 +56,31 @@ export const MapComponent = ({
))}
</g>
<defs>
<linearGradient
id="paint0_linear_235_220192"
x1="-12.1689"
y1="230.282"
x2="188.847"
y2="-168.875"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.143366" stop-color="#D375FF" />
<stop offset="0.771682" stop-color="#798FFF" />
</linearGradient>
<clipPath id="clip0_2181_13226">
<rect width="1063.48" height="554.495" fill="white" />
<rect width="1063.48" height="554.495" />
</clipPath>
<circle cx="7" cy="7" r="6.5" id="crc1" />
</defs>
{federalCities.map((item) => (<FederalCity select={select} handleSelect={handleSelect} key={item.id} item={item}></FederalCity>))}
{federalCities.map((item) => (
<FederalCity
select={select}
handleSelect={handleSelect}
key={item.id}
item={item}
></FederalCity>
))}
</svg>
{open && (
<div className="button-block">
+63 -8
View File
@@ -14,9 +14,10 @@
}
.result-block {
display: flex;
flex-direction: row;
gap: 46px;
height: 105px;
display: flex;
flex-direction: row;
gap: 46px;
}
.result-number {
@@ -30,7 +31,6 @@
}
.result-caption {
font-style: normal;
font-weight: 500;
font-size: 22px;
@@ -58,7 +58,7 @@
font-size: 10px;
line-height: 120%;
/* identical to box height, or 12px */
margin-bottom: 6px;
/* Gray/Accent */
color: #393c46;
@@ -80,6 +80,61 @@
color: #d375ff;
}
.padding {
padding-bottom: 6px;
}
.caption-off {
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 140%;
color: #f7f7f7;
}
.flex-container {
display: flex;
flex-direction: column;
gap: 32px;
}
.title-result {
font-weight: 400;
font-size: 28px;
line-height: 130%;
/* or 36px */
color: #ffffff;
}
.button-result {
padding: 16px 40px 14px;
width: 315px;
height: 55px;
font-weight: 400;
font-size: 16px;
line-height: 125%;
/* identical to box height, or 20px */
letter-spacing: 0.01em;
font-feature-settings: "tnum" on, "lnum" on;
/* Landing/White */
color: #ebebeb;
cursor: pointer;
/* Inside auto layout */
border-radius: 2px;
border: none;
flex: none;
order: 0;
flex-grow: 0;
}
.button_on {
transition: background ease-in 0.2s;
background: #2b5ec6;
}
.button_off {
transition: background ease-in 0.2s;
background: #393c46;
}
+132 -31
View File
@@ -1,11 +1,43 @@
import "./ResultBlock.css";
import { useSelector } from "react-redux";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
export const ResultBlock = () => {
const { timeUpdated, timeDefalut, priceDefault, priceUpdated } = useSelector(
(state) => state.calculationReducer
);
const [turn, setTurn] = useState(false);
const transition = { duration: 0.3, ease: "easeOut" };
const textAnimation = {
open: { opacity: 1, display: "flex", alignItems: "flex-end" },
closed: { opacity: 0, display: "none" },
};
const colorAnimationValue = {
open: { color: "#D375FF", fontSize: "54px", marginRight: "16px" },
closed: { color: "#393c46", fontSize: "24px", marginRight: "8px" },
};
const colorAnimationCaption = {
open: { color: "#D375FF", fontSize: "24px" },
closed: { color: "#393c46", fontSize: "12px" },
};
const colorAnimationValueGreen = {
open: { color: "#219653", fontSize: "54px", marginRight: "16px" },
closed: { color: "#393c46", fontSize: "24px", marginRight: "8px" },
};
const colorAnimationCaptionGreen = {
open: { color: "#219653", fontSize: "24px" },
closed: { color: "#393c46", fontSize: "12px" },
};
const handleMouthPostifx = (num) => {
num = num % 100;
@@ -28,7 +60,7 @@ export const ResultBlock = () => {
};
const handleMounth = (num, type) => {
const monthesPostfixes = [" месяц", " месяца", " месяцев"];
const monthesPostfixes = ["месяц", "месяца", "месяцев"];
let postfix = handleMouthPostifx(num);
let value1 = monthesPostfixes[postfix];
@@ -40,15 +72,13 @@ export const ResultBlock = () => {
if (isNaN(num)) throw new Error(num + " is not a Number!");
let currency = {
0: "",
1: " тыс. руб.",
2: " млн. руб",
3: " млрд. руб",
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];
@@ -59,15 +89,43 @@ export const ResultBlock = () => {
if (type === 1) {
return (
<>
<span className="result-number">{value}</span>
<span className="result-caption">{value1}</span>
<motion.span
transition={transition}
variants={colorAnimationValueGreen}
animate={turn ? "open" : "closed"}
className="result-number_one"
>
{value}
</motion.span>
<motion.span
transition={transition}
variants={colorAnimationCaptionGreen}
animate={turn ? "open" : "closed"}
className="result-caption_one"
>
{value1}
</motion.span>
</>
);
} else if (type === 0) {
return (
<>
<span className="result-number_one">{value}</span>
<span className="result-caption_one">{value1}</span>
<motion.span
transition={transition}
variants={colorAnimationValue}
animate={!turn ? "open" : "closed"}
className="result-number_one"
>
{value}
</motion.span>
<motion.span
transition={transition}
variants={colorAnimationCaption}
animate={!turn ? "open" : "closed"}
className="result-caption_one"
>
{value1}
</motion.span>
</>
);
} else if (type === 3) {
@@ -88,31 +146,74 @@ export const ResultBlock = () => {
};
return (
<div className="result-block">
<div className="result-container">
<div className="numbers-container">
<div className="rub-container">
{handleMounth(Math.round(timeDefalut), 1)}
</div>
<div className="rub-container padding">
{handleMounth(Math.round(timeUpdated), 0)}
<div className="flex-container">
<span className="title-result">Результаты расчета</span>
<div className="result-block">
<div className="result-container">
<div className="numbers-container">
<AnimatePresence>
<motion.div
transition={transition}
variants={textAnimation}
animate={turn ? "open" : "closed"}
>
{handleMounth(Math.round(timeUpdated), 1)}
</motion.div>
</AnimatePresence>
<div
style={turn ? { paddingBottom: "6px" } : { paddingBottom: "0px" }}
className="padding"
>
{handleMounth(Math.round(timeDefalut), 0)}
</div>
</div>
{!turn ? (
<div className="caption-off">На реализацию проекта</div>
) : (
<div>
{" "}
{handleMounth(
Math.round(timeDefalut) - Math.round(timeUpdated),
3
)}
</div>
)}
</div>
<div>
{handleMounth(Math.round(timeDefalut) - Math.round(timeUpdated), 3)}
<div className="result-container">
<div className="numbers-container">
<AnimatePresence>
<motion.div
variants={textAnimation}
animate={turn ? "open" : "closed"}
className="rub-container"
>
{shortenNumRu(Math.round(priceUpdated), 1)}
</motion.div>
</AnimatePresence>
<div
style={turn ? { paddingBottom: "6px" } : { paddingBottom: "0px" }}
className="rub-container"
>
{shortenNumRu(Math.round(priceDefault), 0)}
</div>
</div>
{!turn ? (
<div className="caption-off">На реализацию проекта</div>
) : (
<div>
{shortenNumRu(Math.floor(priceUpdated - priceDefault), 4)}
</div>
)}
</div>
</div>
<div className="result-container">
<div className="numbers-container">
<div className="rub-container">
{shortenNumRu(Math.round(priceUpdated), 1)}
</div>
<div className="rub-container padding">
{shortenNumRu(Math.round(priceDefault), 0)}
</div>
</div>
<div>{shortenNumRu(Math.floor(priceUpdated - priceDefault), 4)}</div>
</div>
<button
className={
turn ? "button-result button_on" : "button-result button_off"
}
onClick={() => setTurn((prev) => !prev)}
>
{!turn ? "Использовать инструмент" : "Отключить инструмент"}
</button>
</div>
);
};
+26 -3
View File
@@ -2,13 +2,36 @@
body {
margin: 0;
font-family: 'GilroyWebRegular';
font-family: "GilroyWebRegular";
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: #0E0E0E;
background: #0e0e0e;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
::-webkit-scrollbar {
width: auto;
}
/* Track */
::-webkit-scrollbar-track {
-webkit-box-shadow: auto;
-webkit-border-radius: auto;
border-radius: auto;
background: auto;
}
/* Handle */
::-webkit-scrollbar-thumb {
-webkit-border-radius: auto;
border-radius: auto;
background: auto;
-webkit-box-shadow: auto;
}
::-webkit-scrollbar-thumb:window-inactive {
background: auto;
}
+14 -1
View File
@@ -12,6 +12,7 @@ const initialState = {
regions: regions,
selectedRegion: {},
options: [],
filteredList: [],
averageNumberApartment: null,
};
@@ -21,7 +22,19 @@ export const calcSlice = createSlice({
reducers: {
handleOptions(state) {
const options = state.regions.filter((i) => i.name);
return { ...state, options: options };
return { ...state, options: options, filteredList: options };
},
handleSearch(state, action) {
const result = state.options.filter((i) => {
const name = String(i.name).toLowerCase().trim();
const userSearch = action.payload.query.toLowerCase().trim();
return name.indexOf(userSearch) !== -1;
});
console.log(action.payload.query);
return { ...state, filteredList: result };
},
handleSelectRegion(state, action) {
const region = state.regions.find((i) => i.id === action.payload);
+33 -34
View File
File diff suppressed because one or more lines are too long