diff --git a/package-lock.json b/package-lock.json index dde0cf3..fdd7385 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,12 +19,12 @@ "@types/react-redux": "^7.1.24", "@types/react-router": "^5.1.20", "@types/socket.io": "^3.0.2", - "connected-react-router": "^6.9.3", "framer-motion": "^7.4.0", "i18next": "^22.4.6", "i18next-browser-languagedetector": "^7.0.1", "i18next-http-backend": "^2.1.1", "js-cookie": "^3.0.1", + "moment": "^2.29.4", "peer": "^0.6.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -5777,26 +5777,6 @@ "node": ">=0.8" } }, - "node_modules/connected-react-router": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.9.3.tgz", - "integrity": "sha512-4ThxysOiv/R2Dc4Cke1eJwjKwH1Y51VDwlOrOfs1LjpdYOVvCNjNkZDayo7+sx42EeGJPQUNchWkjAIJdXGIOQ==", - "dependencies": { - "lodash.isequalwith": "^4.4.0", - "prop-types": "^15.7.2" - }, - "optionalDependencies": { - "immutable": "^3.8.1 || ^4.0.0", - "seamless-immutable": "^7.1.3" - }, - "peerDependencies": { - "history": "^4.7.2", - "react": "^16.4.0 || ^17.0.0", - "react-redux": "^6.0.0 || ^7.1.0", - "react-router": "^4.3.1 || ^5.0.0", - "redux": "^3.6.0 || ^4.0.0" - } - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -8983,12 +8963,6 @@ "url": "https://opencollective.com/immer" } }, - "node_modules/immutable": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", - "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", - "optional": true - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -11710,11 +11684,6 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "node_modules/lodash.isequalwith": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz", - "integrity": "sha512-dcZON0IalGBpRmJBmMkaoV7d3I80R2O+FrzsZyHdNSFrANq/cgDqKQNmAHE8UEj4+QYWwwhkQOVdLHiAopzlsQ==" - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -12018,6 +11987,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -15231,12 +15208,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/seamless-immutable": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/seamless-immutable/-/seamless-immutable-7.1.4.tgz", - "integrity": "sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==", - "optional": true - }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -21618,17 +21589,6 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" }, - "connected-react-router": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.9.3.tgz", - "integrity": "sha512-4ThxysOiv/R2Dc4Cke1eJwjKwH1Y51VDwlOrOfs1LjpdYOVvCNjNkZDayo7+sx42EeGJPQUNchWkjAIJdXGIOQ==", - "requires": { - "immutable": "^3.8.1 || ^4.0.0", - "lodash.isequalwith": "^4.4.0", - "prop-types": "^15.7.2", - "seamless-immutable": "^7.1.3" - } - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -23912,12 +23872,6 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==" }, - "immutable": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", - "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", - "optional": true - }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -25881,11 +25835,6 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, - "lodash.isequalwith": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.isequalwith/-/lodash.isequalwith-4.4.0.tgz", - "integrity": "sha512-dcZON0IalGBpRmJBmMkaoV7d3I80R2O+FrzsZyHdNSFrANq/cgDqKQNmAHE8UEj4+QYWwwhkQOVdLHiAopzlsQ==" - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -26112,6 +26061,11 @@ "minimist": "^1.2.6" } }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -28241,12 +28195,6 @@ "ajv-keywords": "^3.5.2" } }, - "seamless-immutable": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/seamless-immutable/-/seamless-immutable-7.1.4.tgz", - "integrity": "sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==", - "optional": true - }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", diff --git a/package.json b/package.json index 8a12bed..b6136de 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,12 @@ "@types/react-redux": "^7.1.24", "@types/react-router": "^5.1.20", "@types/socket.io": "^3.0.2", - "connected-react-router": "^6.9.3", "framer-motion": "^7.4.0", "i18next": "^22.4.6", "i18next-browser-languagedetector": "^7.0.1", "i18next-http-backend": "^2.1.1", "js-cookie": "^3.0.1", + "moment": "^2.29.4", "peer": "^0.6.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/App.tsx b/src/App.tsx index 9eb88d8..7d9f7e7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import "./App.css"; -import 'styles/styles.css' +import "styles/styles.css"; import { useEffect } from "react"; import { Redirect, Route, Switch, useHistory } from "react-router-dom"; @@ -7,11 +7,11 @@ import { Redirect, Route, Switch, useHistory } from "react-router-dom"; import { useTranslation } from "react-i18next"; import cookies from "js-cookie"; - import { Header } from "components/shared/Header/Header"; import { Card } from "components/pages/Main/Card/Card"; import { PopupComponent } from "components/pages/ConnectPage/PopupComponent/PopupComponent"; import { PlayerComponent } from "components/pages/Stream/PlayerComponent/PlayerComponent"; +import { PlanComponent } from "components/pages/Plan/PlanComponent"; import { useAppDispatch, useAppSelector } from "hooks/redux"; import { fetchCards } from "store/reducers/ActionCreator"; @@ -20,7 +20,6 @@ import { languageSlice } from "store/reducers/languageSlice"; import { ICards } from "models/ICards"; const App: React.FC = () => { - const dispatch = useAppDispatch(); const history = useHistory(); const { handleCurrentCard } = cardSlice.actions; @@ -32,9 +31,6 @@ const App: React.FC = () => { dispatch(handleChangeLanguage(cookies.get("i18next"))); }, []); - useEffect(() => { - window.screen.orientation.lock("landscape"); - }, []); const handleCards = (card: ICards) => { dispatch(handleCurrentCard(card)); history.push("/connect-page"); @@ -74,6 +70,10 @@ const App: React.FC = () => { + +
+ +
); }; diff --git a/src/components/pages/Plan/Aivaz.svg b/src/components/pages/Plan/Aivaz.svg new file mode 100644 index 0000000..372d205 --- /dev/null +++ b/src/components/pages/Plan/Aivaz.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/components/pages/Plan/CalendarComponent/CalendarComponent.css b/src/components/pages/Plan/CalendarComponent/CalendarComponent.css new file mode 100644 index 0000000..af3fce6 --- /dev/null +++ b/src/components/pages/Plan/CalendarComponent/CalendarComponent.css @@ -0,0 +1,46 @@ +.calender-container { + width: 312px; +} + +.weekday-table { + user-select: none; + background: transparent; + cursor: auto; + padding: 3px 5px; + width: 100%; + height: 40px; + border-radius: 4px; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 140%; + color: #f2f2f2; + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; + background-color: transparent; +} + +.calendar { + height: 320px; +} + +.calendar-header { + display: flex; + justify-content: space-between; + margin-bottom: 16px; +} + +.calendar-nav { + border-radius: 8px; + cursor: pointer; +} + +.calendar-nav:hover { + background: rgba(86, 126, 206, 0.2); +} + +.calendar-nav-left { + transform: rotate(180deg); +} diff --git a/src/components/pages/Plan/CalendarComponent/CalendarComponent.tsx b/src/components/pages/Plan/CalendarComponent/CalendarComponent.tsx new file mode 100644 index 0000000..2afaa40 --- /dev/null +++ b/src/components/pages/Plan/CalendarComponent/CalendarComponent.tsx @@ -0,0 +1,136 @@ +import "./CalendarComponent.css"; +import chevron from "images/icons/ChevronRight.svg"; + +import * as moment from "moment"; +import "moment/locale/ru"; +import { motion, useAnimationControls } from "framer-motion"; + +import { useState, useEffect } from "react"; + +import { planSlice } from "store/reducers/planSlice"; +import { useAppDispatch, useAppSelector } from "hooks/redux"; +import { variantsCalendar } from "utils/animationProps.js"; + +export const CalendarComponent: React.FC = ({ time, pickedTime }) => { + const controls = useAnimationControls(); + const dispatch = useAppDispatch(); + const { handleNavigation, handleTimeValue } = planSlice.actions; + + const [calendar, setCalendar] = useState([]); + const [value, setValue] = useState(time); + const currDate = time; + const startDay = value.clone().startOf("month").startOf("week"); + const endDay = value.clone().endOf("month").endOf("week"); + const weekDays = ["ПН", "ВT", "СР", "ЧТ", "ПТ", "СБ", "ВС"]; + + useEffect(() => { + controls.start({ + opacity: 1, + }); + }, [nextMonth, prevMonth]); + + useEffect(() => { + const day = startDay.clone().subtract("1", "day"); + const a = []; + while (day.isBefore(endDay, "day")) { + a.push( + Array(7) + .fill(0) + .map(() => day.add(1, "day").clone()) + ); + } + setCalendar(a); + }, [value]); + + function prevMonth() { + return value.clone().subtract(1, "month"); + } + + function nextMonth() { + return value.clone().add(1, "month").startOf("month"); + } + + function thisMonth() { + return value.isSame(new Date(), "month"); + } + + function hide(day: any) { + if (value.isSame(day, "month")) { + if (currDate.isSame(day, "day")) { + const cellClass = "calendar-cell_active calendar-cell"; + return cellClass; + } + return "calendar-cell calendar-cell_day"; + } else { + return "calendar-cell-none"; + } + } + + const handleValue = (day: moment.Moment) => { + const temp = currDate.clone().subtract(1, "day"); + if (day.isBefore(temp)) { + return; + } else { + dispatch( + handleNavigation({ + isDone: false, + isCalendar: false, + isTimepicker: true, + isForm: false, + }) + ); + dispatch(handleTimeValue(day)); + } + }; + + return ( +
+

Выберите дату.

+
+
+ prev-mouth !thisMonth() && setValue(prevMonth())} + className="calendar-nav calendar-nav-left" + src={chevron} + > + + {value.format("MMMM")}, {value.format("YYYY")} + + next-mouth setValue(nextMonth())} + className="calendar-nav" + src={chevron} + > +
+
+ {weekDays.map((day, i) => ( +
+ {day} +
+ ))} +
+ {calendar.map((week, i) => ( + + {week.map((day: any, i: number) => ( +
handleValue(day)} + className={hide(day)} + > + {day.format("D")} +
+ ))} +
+ ))} +
+
+ ); +}; diff --git a/src/components/pages/Plan/Finish/Finish.css b/src/components/pages/Plan/Finish/Finish.css new file mode 100644 index 0000000..b3fceb3 --- /dev/null +++ b/src/components/pages/Plan/Finish/Finish.css @@ -0,0 +1,26 @@ +.finish-container { + display: flex; + flex-direction: column; + gap: 32px; +} + +.finish-title { + margin: 0; + font-style: normal; + font-weight: 400; + font-size: 38px; + line-height: 100%; + /* or 38px */ + /* White */ + color: #f2f2f2; +} + +.finish-text { + margin: 0; + + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 140%; + color: #c5c7ce; +} diff --git a/src/components/pages/Plan/Finish/Finish.tsx b/src/components/pages/Plan/Finish/Finish.tsx new file mode 100644 index 0000000..94c6da6 --- /dev/null +++ b/src/components/pages/Plan/Finish/Finish.tsx @@ -0,0 +1,16 @@ +import "./Finish.css"; + +export const Finish: React.FC = () => { + return ( +
+

Просмотр запланирован.

+

+ Ссылка для подключения и другая дополнительная информация будут + отправлены на ваш почтовый адрес. +

+ +
+ ); +}; diff --git a/src/components/pages/Plan/Form/Form.css b/src/components/pages/Plan/Form/Form.css new file mode 100644 index 0000000..c56d83f --- /dev/null +++ b/src/components/pages/Plan/Form/Form.css @@ -0,0 +1,42 @@ +.form { + display: flex; + flex-direction: column; + gap: 16px; +} + +.form-input-container { + display: flex; + flex-direction: column; + gap: 4px; +} + +.form-input { + background: #23242a; + box-sizing: border-box; + outline: none; + border-radius: 2px; + padding: 12px 16px; + font-weight: 400; + font-size: 16px; + line-height: 135%; + color: #c5c7ce; + border: 10px solid transparent; + border-image-slice: 1; + border-width: 1px; + +} + +.form-input-caption { + font-weight: 400; + font-size: 14px; + line-height: 140%; + color: #c5c7ce; +} + +.form-input:focus { + border-image-source: linear-gradient(180deg, #bc75ff 0%, #798fff 100%); +} + +.form-input:invalid { + border: 1px solid #E94444; +} \ No newline at end of file diff --git a/src/components/pages/Plan/Form/Form.tsx b/src/components/pages/Plan/Form/Form.tsx new file mode 100644 index 0000000..28ab5db --- /dev/null +++ b/src/components/pages/Plan/Form/Form.tsx @@ -0,0 +1,71 @@ +import chevron from "images/icons/ChevronLeft.svg"; +import "./Form.css"; + +import { planSlice } from "store/reducers/planSlice"; +import { useAppDispatch, useAppSelector } from "hooks/redux"; + +export const Form: React.FC = ({ time }) => { + const dispatch = useAppDispatch(); + const { handleNavigation, handleTimeValue } = planSlice.actions; + + const handleValue = (day: moment.Moment) => { + dispatch( + handleNavigation({ + isDone: false, + isCalendar: false, + isTimepicker: true, + isForm: false, + }) + ); + + dispatch(handleTimeValue(day)); + }; + + const handleReturn = () => { + dispatch( + handleNavigation({ + isDone: false, + isCalendar: false, + isTimepicker: true, + isForm: false, + }) + ); + }; + + return ( +
+

+ Расскажите

о себе. +

+ +
+
+ {time.format("DD MMM, LT")} +
+
+
+ Имя + +
+
+ E-mail + +
+ +
+
+
+ ); +}; diff --git a/src/components/pages/Plan/PlanComponent.css b/src/components/pages/Plan/PlanComponent.css new file mode 100644 index 0000000..f620c06 --- /dev/null +++ b/src/components/pages/Plan/PlanComponent.css @@ -0,0 +1,145 @@ +.content-container-plan { + height: 100vh; + width: 428px; + justify-content: center; + padding: 24px 56px; + position: absolute; + top: 50%; + left: 50%; + box-sizing: border-box; + border-width: 0px 2px; + border-style: solid; + border-color: #23242a; + transform: translate(-50%, -50%); +} + +.calendar-position { + position: relative; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.plan-logo { + width: 158px; + height: 46px; +} + +.plan-title { + margin-top: 0; + margin-bottom: 32px; + font-style: normal; + font-weight: 400; + font-size: 38px; + line-height: 100%; + color: #f2f2f2; +} + +.calendar-date { + font-style: normal; + font-weight: 400; + font-size: 20px; + line-height: 120%; + color: #f2f2f2; + user-select: none; +} + +.calendar-table { + display: grid; + grid-template-columns: repeat(7, 1fr); + justify-content: center; + background: transparent; + gap: 5px; +} + + + +.calendar-table:nth-child(odd) { + background: #1c1d21; +} + +.calendar-cell { + user-select: none; + background: transparent; + cursor: auto; + padding: 3px 5px; + width: 100%; + height: 40px; + border-radius: 4px; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 140%; + color: #f2f2f2; + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; +} + +.calendar-cell_day { + cursor: pointer; +} + +.calendar-cell_day:hover { + background: #23242a; +} + +.calendar-cell-none { + visibility: hidden; +} + +.line-calendar { + margin-top: 32px; + margin-bottom: 16px; +} + +.button-plan { + margin-top: 16px; + margin-bottom: 16px; +} + +.plan-title-plan { + margin: 0; +} + +@media screen and (max-width: 920px) { + .calendar-position { + top: 50%; + } +} + +@media screen and (max-width: 430px) { + + + .content-container-plan { + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + padding: 10px; + } + + .calendar { + width: 100%; + } + + .plan-logo { + display: none; + } + + .plan-title { + margin-top: 32px; + font-style: normal; + font-weight: 400; + font-size: 24px; + line-height: 125%; + white-space: nowrap; + } +} + +@media screen and (max-width: 380px) { + .calendar-position { + top: 60%; + } +} \ No newline at end of file diff --git a/src/components/pages/Plan/PlanComponent.tsx b/src/components/pages/Plan/PlanComponent.tsx new file mode 100644 index 0000000..5852abc --- /dev/null +++ b/src/components/pages/Plan/PlanComponent.tsx @@ -0,0 +1,88 @@ +import "./PlanComponent.css"; +import logo from "./Aivaz.svg"; + +import { useState } from "react"; + +import * as moment from "moment"; +import "moment/locale/ru"; +import { motion, AnimatePresence } from "framer-motion"; + +import { CalendarComponent } from "./CalendarComponent/CalendarComponent"; +import { TimepickerComponent } from "./TimepickerComponent/TimepickerComponent"; +import { Form } from "./Form/Form"; + +import { Finish } from "./Finish/Finish"; +import { useAppSelector } from "hooks/redux"; +import { popupAnimation } from "utils/animationProps"; + +export const PlanComponent: React.FC = () => { + const { isDone, isCalendar, isTimepicker, isForm, time } = useAppSelector( + (state) => state.planReducer + ); + + return ( +
+ logo +
+ + {isCalendar && ( + + + + )} + {isTimepicker && ( + + + + )} + {isForm && ( + +
+
+ )} + {isDone && ( + + + + )} +
+ {!isDone && ( + <> +
+ + + )} +
+
+ ); +}; diff --git a/src/components/pages/Plan/TimepickerComponent/TimepickerComponent.css b/src/components/pages/Plan/TimepickerComponent/TimepickerComponent.css new file mode 100644 index 0000000..520beac --- /dev/null +++ b/src/components/pages/Plan/TimepickerComponent/TimepickerComponent.css @@ -0,0 +1,30 @@ +.button-plan { + margin-top: 16px; + margin-bottom: 16px; +} + +.plan-title-plan { + margin: 0; +} + +.timepicker-cell { + padding: 9px 18px; + width: 72px; + cursor: pointer; +} + +.timepicker-cell:hover { + background: #23242a; +} + +.timepicker-table { + display: grid; + justify-content: center; + background: transparent; + grid-template-columns: repeat(4, 1fr); + gap: 8px; +} + +.timepicker-table:nth-child(even) { + background: #1c1d21; +} diff --git a/src/components/pages/Plan/TimepickerComponent/TimepickerComponent.tsx b/src/components/pages/Plan/TimepickerComponent/TimepickerComponent.tsx new file mode 100644 index 0000000..fa0395e --- /dev/null +++ b/src/components/pages/Plan/TimepickerComponent/TimepickerComponent.tsx @@ -0,0 +1,83 @@ +import chevron from "images/icons/ChevronLeft.svg"; +import "./TimepickerComponent.css"; + +import { planSlice } from "store/reducers/planSlice"; +import { useAppDispatch, useAppSelector } from "hooks/redux"; + +import { useEffect, useState } from "react"; + +export const TimepickerComponent: React.FC = ({ time }) => { + const dispatch = useAppDispatch(); + const { handleNavigation, handleTimeValue } = planSlice.actions; + + const [timePicker, settimePicker] = useState([]); + const startTime = time.clone().hours(8).minutes(0); + const endTime = time.clone().hours(19).minutes(0); + + useEffect(() => { + const temp = startTime.clone().subtract("30", "minute"); + const a = []; + while (temp.isBefore(endTime, "minute")) { + a.push( + Array(8) + .fill(0) + .map(() => temp.add(30, "minutes").clone()) + ); + } + settimePicker(a); + }, [time]); + + const handleValue = (time: moment.Moment) => { + dispatch( + handleNavigation({ + isDone: false, + isCalendar: false, + isTimepicker: false, + isForm: true, + }) + ); + dispatch(handleTimeValue(time)); + }; + + const handleReturn = () => { + dispatch( + handleNavigation({ + isDone: false, + isCalendar: true, + isTimepicker: false, + isForm: false, + }) + ); + }; + return ( +
+

Выберите время.

+ +
+
+ {time.format("DD MMMM")} +
+ {timePicker.map((day, i) => ( +
+ {day.map((time: any, i: number) => ( +
handleValue(time)} + key={i} + className="calendar-cell timepicker-cell" + > + {time.format("LT")} +
+ ))} +
+ ))} +
+
+ ); +}; diff --git a/src/images/icons/ChevronLeft.svg b/src/images/icons/ChevronLeft.svg new file mode 100644 index 0000000..a545424 --- /dev/null +++ b/src/images/icons/ChevronLeft.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/icons/ChevronRight.svg b/src/images/icons/ChevronRight.svg new file mode 100644 index 0000000..fa19293 --- /dev/null +++ b/src/images/icons/ChevronRight.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/store/reducers/planSlice.ts b/src/store/reducers/planSlice.ts new file mode 100644 index 0000000..abc56cd --- /dev/null +++ b/src/store/reducers/planSlice.ts @@ -0,0 +1,50 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { Moment } from "moment"; +import * as moment from "moment"; +import "moment/locale/ru"; + +interface IState { + isCalendar: boolean; + isTimepicker: boolean; + isForm: boolean; + isDone: boolean; +} + +export interface planState { + time: Moment; + isCalendar: boolean; + isTimepicker: boolean; + isForm: boolean; + isDone: boolean; + email: string; + name: string; +} + +const initialState: planState = { + time: moment.default(), + isCalendar: true, + isTimepicker: false, + isForm: false, + isDone: false, + email: "", + name: "", +}; + +export const planSlice = createSlice({ + name: "plan", + initialState, + reducers: { + handleNavigation(state, action: PayloadAction) { + state.isCalendar = action.payload.isCalendar; + state.isDone = action.payload.isDone; + state.isTimepicker = action.payload.isTimepicker; + state.isForm = action.payload.isForm; + }, + + handleTimeValue(state, action: PayloadAction) { + state.time = action.payload; + }, + }, +}); + +export default planSlice.reducer; diff --git a/src/store/store.ts b/src/store/store.ts index e4e825e..4f6a2d1 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -1,18 +1,22 @@ import { combineReducers, configureStore } from "@reduxjs/toolkit"; + import cardReducer from "./reducers/cardSlice"; import sessionReducer from "./reducers/sessionSlice"; import languageReducer from "./reducers/languageSlice"; - +import planReducer from "./reducers/planSlice"; const rootReducer = combineReducers({ cardReducer, sessionReducer, languageReducer, + planReducer, }); export const setupStore = () => { return configureStore({ reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ serializableCheck: false }), }); }; diff --git a/src/styles/styles.css b/src/styles/styles.css index 010d775..9ab77fb 100644 --- a/src/styles/styles.css +++ b/src/styles/styles.css @@ -57,3 +57,23 @@ color: #f2f2f2; background: #73788c; } + +.button-type-small { + transition: background 0.2s ease-in-out; + + font-style: normal; + font-weight: 400; + font-size: 12px; + line-height: 130%; + color: #c5c7ce; + background: #1c1d21; + border-radius: 4px; + padding: 8px 16px; +} + +.button-type-small:hover { + transition: background 0.2s ease-in-out; + + background: #23242a; + color: #f2f2f2; +} diff --git a/src/utils/animationProps.js b/src/utils/animationProps.js index 886612e..36429da 100644 --- a/src/utils/animationProps.js +++ b/src/utils/animationProps.js @@ -13,6 +13,11 @@ export const animationButton = { }, }; +export const variantsCalendar = { + visible: { opacity: 1, transition: { duration: 1, ease: "easeOut" } }, + hidden: { opacity: 0, transition: { duration: 1, ease: "easeOut" } }, +}; + export const sidebarVariants = { open: { x: -1, transition: { ease: "easeIn" }, width: "60px" }, closed: { x: "-50px", transition: { ease: "easeIn" }, width: "60px" },