diff --git a/.hintrc b/.hintrc new file mode 100644 index 00000000..cb34607d --- /dev/null +++ b/.hintrc @@ -0,0 +1,8 @@ +{ + "extends": [ + "development" + ], + "hints": { + "no-inline-styles": "off" + } +} \ No newline at end of file diff --git a/functions/package-lock.json b/functions/package-lock.json index ef729789..fff55b1b 100644 --- a/functions/package-lock.json +++ b/functions/package-lock.json @@ -7,7 +7,7 @@ "name": "functions", "dependencies": { "@google/generative-ai": "^0.15.0", - "delib-npm": "^1.3.44", + "delib-npm": "^1.3.47", "dotenv": "^16.4.5", "firebase-admin": "^11.8.0", "firebase-functions": "^5.1.0", @@ -3288,9 +3288,10 @@ } }, "node_modules/delib-npm": { - "version": "1.3.44", - "resolved": "https://registry.npmjs.org/delib-npm/-/delib-npm-1.3.44.tgz", - "integrity": "sha512-6/5LMhuJ4lekGRVc4sChA6SRgEOxaXUySdswrkENlBMi1htrL8+6aM9zlX/ExJgjfzpOo8cgpibKKyKpENipOQ==", + "version": "1.3.47", + "resolved": "https://registry.npmjs.org/delib-npm/-/delib-npm-1.3.47.tgz", + "integrity": "sha512-/MSPA+Hlae4C175YyHMfU7oMPWvn0x/mzGbZ06KoZeWemPrOHygCvepRxfjBi+8LKmA2MuJQ7Jzp86ENuDGuvQ==", + "license": "ISC", "dependencies": { "react": "^18.3.1", "sass": "^1.77.6", diff --git a/functions/package.json b/functions/package.json index b3da16ab..0c5ff7a5 100644 --- a/functions/package.json +++ b/functions/package.json @@ -16,7 +16,7 @@ "main": "lib/index.js", "dependencies": { "@google/generative-ai": "^0.15.0", - "delib-npm": "^1.3.44", + "delib-npm": "^1.3.47", "dotenv": "^16.4.5", "firebase-admin": "^11.8.0", "firebase-functions": "^5.1.0", diff --git a/package-lock.json b/package-lock.json index 8f4b59db..58835796 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@dagrejs/dagre": "^1.0.4", "@reduxjs/toolkit": "^1.9.5", - "delib-npm": "^1.3.46", + "delib-npm": "^1.3.47", "eslint-plugin-import": "^2.29.1", "eslint-plugin-sonarjs": "^1.0.3", "firebase": "^10.0.0", @@ -5486,9 +5486,10 @@ } }, "node_modules/delib-npm": { - "version": "1.3.46", - "resolved": "https://registry.npmjs.org/delib-npm/-/delib-npm-1.3.46.tgz", - "integrity": "sha512-zOaIOguKki8p1mNbtSRjDRk0zNZrTVNCxRnPTEd3S3eoAmYrLljEJy3aIw2xrQceYfEwy+SQWPHG3KQTOJd31w==", + "version": "1.3.47", + "resolved": "https://registry.npmjs.org/delib-npm/-/delib-npm-1.3.47.tgz", + "integrity": "sha512-/MSPA+Hlae4C175YyHMfU7oMPWvn0x/mzGbZ06KoZeWemPrOHygCvepRxfjBi+8LKmA2MuJQ7Jzp86ENuDGuvQ==", + "license": "ISC", "dependencies": { "react": "^18.3.1", "sass": "^1.77.6", diff --git a/package.json b/package.json index 93e5ad43..af2da9be 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "@dagrejs/dagre": "^1.0.4", "@reduxjs/toolkit": "^1.9.5", - "delib-npm": "^1.3.46", + "delib-npm": "^1.3.47", "eslint-plugin-import": "^2.29.1", "eslint-plugin-sonarjs": "^1.0.3", "firebase": "^10.0.0", diff --git a/src/assets/icons/Frame 1171276030.svg b/src/assets/icons/Frame 1171276030.svg new file mode 100644 index 00000000..0f714392 --- /dev/null +++ b/src/assets/icons/Frame 1171276030.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/Group 2.svg b/src/assets/icons/Group 2.svg new file mode 100644 index 00000000..a0f508f7 --- /dev/null +++ b/src/assets/icons/Group 2.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/Rectangle 3.svg b/src/assets/icons/Rectangle 3.svg new file mode 100644 index 00000000..5b7a1fb3 --- /dev/null +++ b/src/assets/icons/Rectangle 3.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/green1.svg b/src/assets/icons/green1.svg new file mode 100644 index 00000000..0e29c5c6 --- /dev/null +++ b/src/assets/icons/green1.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/x-icon.svg b/src/assets/icons/x-icon.svg new file mode 100644 index 00000000..c7130340 --- /dev/null +++ b/src/assets/icons/x-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/Enable the Notifications button to grant permission.svg b/src/assets/images/Enable the Notifications button to grant permission.svg new file mode 100644 index 00000000..b9bf7ef7 --- /dev/null +++ b/src/assets/images/Enable the Notifications button to grant permission.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/Frame 1171276040.svg b/src/assets/images/Frame 1171276040.svg new file mode 100644 index 00000000..e9e10011 --- /dev/null +++ b/src/assets/images/Frame 1171276040.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/Snackbar.svg b/src/assets/images/Snackbar.svg new file mode 100644 index 00000000..8e9e1c05 --- /dev/null +++ b/src/assets/images/Snackbar.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/Snackbar2page.svg b/src/assets/images/Snackbar2page.svg new file mode 100644 index 00000000..46ca5763 --- /dev/null +++ b/src/assets/images/Snackbar2page.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/Web Settings.svg b/src/assets/images/Web Settings.svg new file mode 100644 index 00000000..161d78c4 --- /dev/null +++ b/src/assets/images/Web Settings.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/poiner 1.png b/src/assets/images/poiner 1.png new file mode 100644 index 00000000..7ce157d6 Binary files /dev/null and b/src/assets/images/poiner 1.png differ diff --git a/src/assets/images/poiner 1.svg b/src/assets/images/poiner 1.svg new file mode 100644 index 00000000..2c0ee0c8 --- /dev/null +++ b/src/assets/images/poiner 1.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/reset permission.png b/src/assets/images/reset permission.png new file mode 100644 index 00000000..4d058ff8 Binary files /dev/null and b/src/assets/images/reset permission.png differ diff --git a/src/assets/images/sentence.svg b/src/assets/images/sentence.svg new file mode 100644 index 00000000..3b5a26d7 --- /dev/null +++ b/src/assets/images/sentence.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/woman pointing.svg b/src/assets/images/woman pointing.svg new file mode 100644 index 00000000..50456274 --- /dev/null +++ b/src/assets/images/woman pointing.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/woman.png b/src/assets/images/woman.png new file mode 100644 index 00000000..1a41181f Binary files /dev/null and b/src/assets/images/woman.png differ diff --git a/src/controllers/db/configKey.ts b/src/controllers/db/configKey.ts index 02251b0b..319891b2 100644 --- a/src/controllers/db/configKey.ts +++ b/src/controllers/db/configKey.ts @@ -1,6 +1,5 @@ const mode = import.meta.env.VITE_APP_ENV as 'development' | 'production'; -console.log("mode", mode); const firebaseConfig = { development: { apiKey: import.meta.env.VITE_FIREBASE_API_KEY_DEV, diff --git a/src/controllers/db/vote/getVotes.ts b/src/controllers/db/vote/getVotes.ts index 164211ee..245f5153 100644 --- a/src/controllers/db/vote/getVotes.ts +++ b/src/controllers/db/vote/getVotes.ts @@ -1,10 +1,10 @@ import { - collection, - doc, - getDoc, - getDocs, - query, - where, + collection, + doc, + getDoc, + getDocs, + query, + where, } from "firebase/firestore"; import { Collections, Statement, StatementSchema, Vote } from "delib-npm"; import { DB } from "../config"; @@ -14,52 +14,52 @@ import { store } from "@/model/store"; // Why get user from firebase when we can pass it as a parameter? export async function getToVoteOnParent( - parentId: string, - updateStoreWithVoteCB: (statement: Statement) => void + parentId: string, + updateStoreWithVoteCB: (statement: Statement) => void ): Promise { - try { - const user = getUserFromFirebase(); - if (!user) throw new Error("User not logged in"); - if (!parentId) throw new Error("ParentId not provided"); - const voteId = getVoteId(user.uid, parentId); - if (!voteId) throw new Error("VoteId not found"); + try { + const user = getUserFromFirebase(); + if (!user) throw new Error("User not logged in"); + if (!parentId) throw new Error("ParentId not provided"); + const voteId = getVoteId(user.uid, parentId); + if (!voteId) throw new Error("VoteId not found"); - const parentVoteRef = doc(DB, Collections.votes, voteId); + const parentVoteRef = doc(DB, Collections.votes, voteId); - const voteDB = await getDoc(parentVoteRef); + const voteDB = await getDoc(parentVoteRef); - const vote = voteDB.data(); - if (!vote) return; - VoteSchema.parse(vote); + const vote = voteDB.data(); + if (!vote) return; + VoteSchema.parse(vote); - //get statemtn to update to store - const statementRef = doc(DB, Collections.statements, vote.statementId); - const statementDB = await getDoc(statementRef); + //get statemtn to update to store + const statementRef = doc(DB, Collections.statements, vote.statementId); + const statementDB = await getDoc(statementRef); - const statement = statementDB.data() as Statement; - if (!statement) throw new Error("Parent not found"); - StatementSchema.parse(statement); + const statement = statementDB.data() as Statement; + if (!statement) throw new Error("Parent not found"); + StatementSchema.parse(statement); - updateStoreWithVoteCB(statement); - } catch (error) { - console.error(error); - } + updateStoreWithVoteCB(statement); + } catch (error) { + console.error(error); + } } export async function getVoters(parentId: string): Promise { - try { - const user = store.getState().user.user; - if (!user) throw new Error("User not logged in"); - const votesRef = collection(DB, Collections.votes); - const q = query(votesRef, where("parentId", "==", parentId)); + try { + const user = store.getState().user.user; + if (!user) throw new Error("User not logged in"); + const votesRef = collection(DB, Collections.votes); + const q = query(votesRef, where("parentId", "==", parentId)); - const votersDB = await getDocs(q); - const voters = votersDB.docs.map((vote) => vote.data()) as Vote[]; + const votersDB = await getDocs(q); + const voters = votersDB.docs.map((vote) => vote.data()) as Vote[]; - return voters; - } catch (error) { - console.error(error); + return voters; + } catch (error) { + console.error(error); - return [] as Vote[]; - } + return [] as Vote[]; + } } diff --git a/src/view/components/enableNotifications/EnableNotifications.tsx b/src/view/components/enableNotifications/EnableNotifications.tsx index 7a7799fd..28bf5ccd 100644 --- a/src/view/components/enableNotifications/EnableNotifications.tsx +++ b/src/view/components/enableNotifications/EnableNotifications.tsx @@ -1,9 +1,8 @@ -import "./enableNotifications.scss"; -import NotificationsGraphic from "@/assets/svg-graphics/notifications.svg?react"; +import React, { useState, useEffect } from 'react'; +import PageNotifications1 from './PageNotifications1'; +import PageNotifications2 from './PageNotifications2'; import Modal from "../modal/Modal"; -import { setStatementSubscriptionToDB } from "@/controllers/db/subscriptions/setSubscriptions"; -import { Role, Statement } from "delib-npm"; -import { setStatementSubscriptionNotificationToDB } from "@/controllers/db/notifications/notifications"; +import { Statement } from "delib-npm"; interface Props { setAskNotifications: React.Dispatch>; @@ -11,71 +10,25 @@ interface Props { setShowAskPermission: React.Dispatch>; } -export default function EnableNotifications({ - setAskNotifications, - statement, - setShowAskPermission, -}: Props) { +export default function Enablenotifications({ setAskNotifications, statement, setShowAskPermission }: Props) { if (!statement) throw new Error("No statement"); - const userAskedForNotification = true; - const getNotifications = true; + const [currentPage, setCurrentPage] = useState(1); - const handleCancelClick = async () => { - await setStatementSubscriptionToDB( - statement, - Role.admin, - userAskedForNotification, - ); - setAskNotifications(false); - }; - - const handleEnableNotificationsClick = async () => { - const permission = await Notification.requestPermission(); - - if (permission === "granted") - await setStatementSubscriptionNotificationToDB( - statement, - getNotifications, - ); - else setShowAskPermission(true); + useEffect(() => { + setCurrentPage(1); + }, []); - await setStatementSubscriptionToDB( - statement, - Role.admin, - userAskedForNotification, - ); - - setAskNotifications(false); + const handleNext = () => { + setCurrentPage(2); }; return ( -
- -

Don'T Miss Out!

-

- Enable push notifications to stay updated on messages -

-
- - -
+
+ {currentPage === 1 && } + {currentPage === 2 && }
); -} +} \ No newline at end of file diff --git a/src/view/components/enableNotifications/PageNotifications1.tsx b/src/view/components/enableNotifications/PageNotifications1.tsx new file mode 100644 index 00000000..51dbb80f --- /dev/null +++ b/src/view/components/enableNotifications/PageNotifications1.tsx @@ -0,0 +1,74 @@ +import React, { useState } from 'react'; +import "./pageNotifications1.scss"; +import pointer1 from "@/assets/images/poiner 1.svg"; +import Elipse3 from "@/assets/icons/Group 2.svg"; +import Frame from "@/assets/icons/Frame 1171276030.svg"; +import Rectangle from "@/assets/icons/Rectangle 3.svg"; +import rectangleText from "@/assets/images/Snackbar.svg"; +import sentence from "@/assets/images/sentence.svg"; +import link from "@/assets/images/Web Settings.svg"; +import xicon from "@/assets/icons/x-icon.svg"; +import Modal from "../modal/Modal"; +import { Statement } from "delib-npm"; + +interface Props { + onNext: () => void; + setAskNotifications: React.Dispatch>; + statement: Statement | undefined; + setShowAskPermission: React.Dispatch>; +} +export default function PageNotifications1({ onNext, setAskNotifications, statement }: Props) { + if (!statement) throw new Error("No statement"); + + const [isModalOpen, setIsModalOpen] = useState(true); + + const handleClose = () => { + setAskNotifications(false); setIsModalOpen(false);}; + + return ( + <> +
+ {isModalOpen && ( + +
+
+
+
+ Ellipse + Rectangle + Frame +
+
+ xicon +
+
+
+ Sentence + Rectangle +
+ Link +
+
+ Pointer +
+

+ Select the Option icon in your browser's address bar +

+
+
+ + + +
+
+
+
+ )} +
+ + ); +} \ No newline at end of file diff --git a/src/view/components/enableNotifications/PageNotifications2.tsx b/src/view/components/enableNotifications/PageNotifications2.tsx new file mode 100644 index 00000000..3014e34c --- /dev/null +++ b/src/view/components/enableNotifications/PageNotifications2.tsx @@ -0,0 +1,78 @@ +import React, { useState } from 'react'; +import "./pageNotifications2.scss"; +import pointer1 from "@/assets/images/woman pointing.svg"; +import Green1 from "@/assets/icons/green1.svg"; +import Elipse3 from "@/assets/icons/Group 2.svg"; +import Rectangle from "@/assets/icons/Rectangle 3.svg"; +import rectangleText from "@/assets/images/Snackbar2page.svg"; +import sentence from "@/assets/images/Enable the Notifications button to grant permission.svg"; +import resetpermission from "@/assets/images/reset permission.png"; +import link from "@/assets/images/Frame 1171276040.svg"; +import xicon from "@/assets/icons/x-icon.svg"; +import Modal from "../modal/Modal"; +import { Statement } from "delib-npm"; + +interface Props { statement: Statement | undefined; + setCurrentPage: React.Dispatch>; + setAskNotifications: React.Dispatch>; + setShowAskPermission: React.Dispatch>; +} + +export default function PageNotifications2({ statement, setCurrentPage, setAskNotifications }: Props) { + if (!statement) throw new Error("No statement"); + + const [isModalOpen, setIsModalOpen] = useState(true); + + const handleClose = () => {setAskNotifications(false); setIsModalOpen(false); }; + const handleBack = () => { setCurrentPage(1); }; + + return ( + <> +
+ {isModalOpen && ( + +
+
+
+
+ Green1 + Rectangle + Ellipse +
+
+ xicon +
+
+
+ Sentence + Rectangle +
+ Link +
+
+ reset-permission +
+
+ Pointer +
+
+

Turn Notifications on

+
+
+
+ + + +
+
+
+
+ )} +
+ + ); +} diff --git a/src/view/components/enableNotifications/enableNotifications.scss b/src/view/components/enableNotifications/enableNotifications.scss deleted file mode 100644 index a123f0dd..00000000 --- a/src/view/components/enableNotifications/enableNotifications.scss +++ /dev/null @@ -1,53 +0,0 @@ -.enableNotifications { - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-between; - gap: 1.1rem; - direction: ltr; - - svg { - margin-top: -60px; - margin-bottom: 20px; - } - - &__title { - font-size: 1.2rem; - font-weight: 600; - color: #3b4f7d; - } - &__text { - color: #657bad; - text-align: center; - font-family: "Roboto"; - font-size: 0.9rem; - font-style: normal; - font-weight: 400; - line-height: 19px; /* 135.714% */ - letter-spacing: 0.5px; - width: 60%; - padding-bottom: 30px; - } - &__btnBox { - width: 100%; - display: grid; - grid-template-columns: 2fr 3fr; - box-shadow: 0 -3px 3px var(--shadow); - - button { - font-family: "Roboto"; - font-weight: 600; - } - &__cancel { - border-radius: 0 0 0 10px; - color: #ee6565; - background-color: inherit; - padding: 1rem; - } - &__enable { - border-radius: 0 0 6px 0; - background-color: #4e88c7; - color: #fff; - } - } -} diff --git a/src/view/components/enableNotifications/pageNotifications1.scss b/src/view/components/enableNotifications/pageNotifications1.scss new file mode 100644 index 00000000..14f823f1 --- /dev/null +++ b/src/view/components/enableNotifications/pageNotifications1.scss @@ -0,0 +1,329 @@ +.enableNotifications { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + gap: 13.8rem; + direction: ltr; + + .popup { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + } + .popup-content { + position: relative; + width: 100%; + width: 121.2vh; + height: 100vh; + min-width: 24.35rem; + background: var(--statementBackground); + box-shadow: 0rem 15rem 5rem rgba(107, 121, 149, 0.02), 0rem 8rem 4rem rgba(118, 133, 160, 0.07), 0rem 3rem 3rem rgba(118, 133, 160, 0.11), 0rem 1rem 2rem rgba(118, 133, 160, 0.13); + border-radius: 0; + display: flex; + justify-content: center; + padding: 0; + margin: 0 auto; + padding: 1.25rem; + } + @media only screen and (min-width: 780px) { + .popup-content { + position: absolute; + width: 68.1875rem; + height: 55.9375rem; + left: calc(50% - 68.1875rem/2 + 0.03125rem); + top: calc(50% - 55.9375rem/2 + 0.65625rem); + border-radius: 0.5rem; + } + } + .step-group { + position: absolute; + top: 1.3rem; + left: 9.4rem; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + gap: 0.5rem; + } + + .step-group img:first-child { + margin-top: 0.5rem; + } + + .step-group img:nth-child(2) { + margin-left: -1rem; +} +.step-group img:nth-child(3) { + margin-left: -0.75rem; +} +@media only screen and (min-width: 780px) { + .step-group { + transform: scale(1.2); + left: 45%; + } +} + .icons-close-false { + position: absolute; + margin-left: 9.7rem; + margin-top: 0.75rem; + cursor: pointer; + } + @media only screen and (min-width: 780px) { + .icons-close-false { + position: absolute; + top: 1.05rem; + right: 3rem; + cursor: pointer; + transform: scale(1.2); + } + } + @media only screen and (max-width: 361px) { + .icons-close-false { + margin-left: 8.5rem; + margin-top: 0.45rem; + } + } + .popup-body { + position: absolute; + max-width: 21.25rem; + height: 8.0625rem; + top: 6.75rem; + margin: 0 auto; + margin-bottom: 1.25rem; + flex: 1; + } + .rectangle-text { + } + .desktop-image { + position: absolute; + display: block; + position: relative; + left: -9.375rem; + margin: 0 auto; + } + .mobile-image { + display: none; + } + + @media only screen and (max-width: 780px) { + .desktop-image { + display: none; + } + .mobile-image { + display: block; + } + } + .link-wrapper { + position: absolute; + top: 7.9rem; + left: 40%; + transform: translateX(-50%); + margin-bottom: 1.25rem; + + @media only screen and (max-width: 361px) { + top: 86%; + left: -25%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.7); + transform-origin: center; + } + } + .pointer-container { + position: absolute; + top: 270%; + left: 6.2rem; + transform: translateY(-50%); + display: flex; + justify-content: center; + align-items: center; + + @media only screen and (max-width: 361px) { + top: 110%; + left: 33.5%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.65); + transform-origin: center; + } + @media only screen and (min-width: 540px) { + top: 150%; + left: 33.5%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.65); + transform-origin: center; + } +} + + .option-icon-text { + position: absolute; + width: 100%; + height: 3.75rem; + left: 0; + top: 32.375rem; + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-size: 1.25rem; + line-height: 150%; + color: var(--body-dark); + text-align: left; + + @media (max-width: 541px) { + margin-top: -8rem; + text-align: left; + font-size: 1rem; + } + @media (max-width: 435px) { + margin-top: 1.7rem; + text-align: left; + font-size: 1.2rem; + } + @media only screen and (max-width: 412px) { + margin-top: 1rem; + text-align: left; + font-size: 1.2rem; + } + @media (max-width: 417px) { + margin-top: -5.1rem; + text-align: left; + font-size: 1rem; + } + @media (max-width: 395px) { + margin-top: -2rem; + text-align: left; + font-size: 1rem; + } + @media (max-width: 365px) { + margin-top: -5rem; + text-align: left; + font-size: 0.9rem; + } + @media (max-width: 361px) { + font-size: 1rem; + margin-top: -53%; + margin-left: 1rem; + } + } + .option-text { + color: #5F88E5; + } + .popup-footer { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + padding: 0rem; + gap: 9.625rem; + position: absolute; + width: 18.625rem; + height: 5rem; + left: calc(50% - 18.625rem/2); + bottom: 2.5rem; + margin: 0 auto; + bottom: 2.5rem; + left: 50%; + transform: translateX(-50%); + } + .close-button { + box-sizing: border-box; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 0.4rem 1rem; + gap: 1rem; + margin: 0 auto; + width: 4rem; + height: 2rem; + + flex: none; + order: 0; + flex-grow: 0; + + border: 1px solid #D1D5DB; + border-radius: 1.25rem; + + border: 0.0625rem solid #739EE4; + filter: drop-shadow(0rem 2.875rem 1.125rem rgba(115, 138, 191, 0.01)) drop-shadow(0rem 1.625rem 1rem rgba(115, 138, 191, 0.05)) drop-shadow(0rem 0.6875rem 0.6875rem rgba(115, 138, 191, 0.09)) drop-shadow(0rem 0.1875rem 0.375rem rgba(115, 138, 191, 0.1)); + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-size: 1rem; + line-height: 1.25rem; + letter-spacing: 0.0146491rem; + color: #5F88E5; + + flex: none; + order: 0; + flex-grow: 0; + } + .close-button:hover { + background: #739EE4; + color: #FFFFFF; + } + .next-button { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 0.4rem 1rem; + gap: 1rem; + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-size: 1rem; + line-height: 1.25rem; + letter-spacing: 0.0146491rem; + color: #FFFFFF; + + margin: 0 auto; + width: 4rem; + height: 2rem;; + + background: #739EE4; + box-shadow: 0px 1rem 0.4rem rgba(38, 56, 84, 0.01), 0px 0.6rem 0.4rem rgba(38, 56, 84, 0.05), 0px 0.2rem 0.2rem rgba(38, 56, 84, 0.09), 0px 0.1rem 0.1rem rgba(38, 56, 84, 0.1); + border-radius: 1.25rem; + + flex: none; + order: 1; + flex-grow: 0; + } + + @media only screen and (min-width: 780px) { + + .option-icon-text { + font-size: 1.375rem; + white-space: nowrap; + position: absolute; + left: -30%; + transform: translateX(-50%); + transform: translateY(-50%); + } + + .popup-footer { + display: flex; + justify-content: center; + align-items: center; + gap: 20rem; + } + + .close-button, .next-button { + width: 6.625rem; + height: 2.6875rem; + padding: var(--Spacing12) var(--Spacing36) var(--Spacing12) var(--Spacing36); + gap: 0.625rem; + border-radius: 1.25rem; + opacity: 1; + } + } +} + diff --git a/src/view/components/enableNotifications/pageNotifications2.scss b/src/view/components/enableNotifications/pageNotifications2.scss new file mode 100644 index 00000000..f24e6161 --- /dev/null +++ b/src/view/components/enableNotifications/pageNotifications2.scss @@ -0,0 +1,398 @@ +.enableNotificationspage2 { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + gap: 13.8rem; + direction: ltr; + + .popup { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + } + + .popup-content { + position: relative; + width: 100%; + width: 121.2vh; + height: 100vh; + min-width: 24.35rem; + background: var(--statementBackground); + box-shadow: 0rem 15rem 5rem rgba(107, 121, 149, 0.02), 0rem 8rem 4rem rgba(118, 133, 160, 0.07), 0rem 3rem 3rem rgba(118, 133, 160, 0.11), 0rem 1rem 2rem rgba(118, 133, 160, 0.13); + border-radius: 0; + display: flex; + justify-content: center; + padding: 0; + margin: 0 auto; + padding: 1.25rem; + } + @media only screen and (min-width: 780px) { + .popup-content { + position: absolute; + width: 68.1875rem; + height: 55.9375rem; + left: calc(50% - 68.1875rem/2 + 0.03125rem); + top: calc(50% - 55.9375rem/2 + 0.65625rem); + border-radius: 0.5rem; + } + } + .step-group { + position: absolute; + top: 1.3rem; + left: 9.4rem; + left: 30%; + transform: translateX(-50%); + display: flex; + align-items: center; + gap: 0.5rem; + } + .step-group img:first-child { + margin-top: 0.23rem; + width: 32.3%; + height: auto; + } + .step-group img:nth-child(2) { + margin-left: -1.072rem; +} +.step-group img:nth-child(3) { + margin-left: -0.97rem; +} + +@media only screen and (min-width: 780px) { + .step-group { + transform: scale(1.2); + left: 45%; + } +} +@media only screen and (max-width: 775px) { + .step-group { + margin-left: 6.2rem; + } +} +@media only screen and (max-width: 769px) { + .step-group { + margin-left: 14.2rem; + } +} +@media only screen and (max-width: 768px) { + .step-group { + margin-left: 6.2rem; + } +} + .icons-close-false { + position: absolute; + margin-left: 9.7rem; + margin-top: 0.75rem; + cursor: pointer; + } + @media only screen and (min-width: 780px) { + .icons-close-false { + position: absolute; + top: 1.05rem; + right: 3rem; + cursor: pointer; + transform: scale(1.2); + } + } + @media only screen and (max-width: 361px) { + .icons-close-false { + margin-left: 8.5rem; + margin-top: 0.45rem; + } + } + .popup-body { + position: absolute; + max-width: 21.25rem; + height: 8.0625rem; + top: 6.75rem; + margin: 0 auto; + margin-bottom: 1.25rem; + flex: 1; + } + .desktop-image { + position: absolute; + display: block; + position: relative; + left: -5rem; + margin: 0 auto; + } + .mobile-image { + display: none; + } + @media only screen and (max-width: 780px) { + .desktop-image { + display: none; + } + .mobile-image { + display: block; + } + } + .link-wrapper { + position: absolute; + top: 7.9rem; + left: 45%; + transform: translateX(-50%); + margin-bottom: 1.25rem; + + @media only screen and (max-width: 431px) { + top: 90%; + left: -6%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.90); + transform-origin: center; + } + @media only screen and (max-width: 415px) { + top: 90%; + left: -6%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.85); + transform-origin: center; + } + @media only screen and (max-width: 361px) { + top: 90%; + left: -6%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.85); + transform-origin: center; + } + @media only screen and (max-width: 391px) { + top: 90%; + left: -6%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.85); + transform-origin: center; + } + } + .reset-permission { + position: absolute; + top: 11.9rem; + left: 30.5%; + transform: translateX(-50%); + margin-bottom: 10.25rem; + } + .pointer-container { + position: absolute; + top: 267%; + left: 6.8rem; + transform: translateY(-50%); + display: flex; + justify-content: center; + align-items: center; + + @media only screen and (max-width: 415px) { + top: 80%; + left: 34%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.72); + transform-origin: center; + } + @media only screen and (max-width: 413px) { + top: 120%; + left: 30%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(1); + transform-origin: center; + } + @media only screen and (max-width: 361px) { + top: 70%; + left: 36%; + transform: translate(-50%, -50%); + margin-bottom: 0; + transform: scale(0.62); + transform-origin: center; + } +} + .option-icon-text { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-size: 1.25rem; + line-height: 150%; + color: var(--body-dark); + text-align: left; + margin-top: 1.7rem; + margin-left: 5rem; + + @media only screen and (max-width: 780px) { + font-size: 1.4rem; + margin-top: 185%; + margin-left: 1.5rem; + } + @media only screen and (max-width: 769px) { + font-size: 1.2rem; + margin-top: 145%; + margin-left: 1.5rem; + } + @media (max-width: 435px) { + font-size: 1.2rem; + margin-top: 32rem; + margin-left: 2rem; + } + @media (max-width: 417px) { + font-size: 1rem; + margin-top: 32rem; + margin-left: 2rem; + } + @media (max-width: 415px) { + font-size: 1.2rem; + margin-top: 22rem; + margin-left: 2rem; + } + @media (max-width: 413px) { + font-size: 1.2rem; + margin-top: 32rem; + margin-left: 2rem; + } + @media (max-width: 395px) { + font-size: 1rem; + } + @media (max-width: 391px) { + font-size: 1.1rem; + margin-top: 135%; + margin-left: 1.5rem; + } + @media (max-width: 365px) { + font-size: 0.9rem; + } + @media (max-width: 361px) { + font-size: 0.9rem; + margin-top: 18rem; + margin-left: 1rem; + } + } + .option-text { + color: var(--body-dark); + } + .popup-footer { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + padding: 0rem; + gap: 9.625rem; + position: absolute; + width: 18.625rem; + height: 5rem; + left: calc(50% - 18.625rem/2); + bottom: 2.5rem; + margin: 0 auto; + bottom: 2.5rem; + left: 50%; + transform: translateX(-50%); + } + .back-button { + box-sizing: border-box; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 0.4rem 1rem; + gap: 1rem; + margin: 0 auto; + width: 4rem; + height: 2rem; + + flex: none; + order: 0; + flex-grow: 0; + + border: 1px solid #D1D5DB; + border-radius: 1.25rem; + + border: 0.0625rem solid var(--button-blue); + filter: drop-shadow(0rem 2.875rem 1.125rem rgba(115, 138, 191, 0.01)) drop-shadow(0rem 1.625rem 1rem rgba(115, 138, 191, 0.05)) drop-shadow(0rem 0.6875rem 0.6875rem rgba(115, 138, 191, 0.09)) drop-shadow(0rem 0.1875rem 0.375rem rgba(115, 138, 191, 0.1)); + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-size: 1rem; + line-height: 1.25rem; + letter-spacing: 0.0146491rem; + color: #5F88E5; + + flex: none; + order: 0; + flex-grow: 0; + } + .back-button:hover { + background: var(--button-blue); + color: var(--white); + } + .finish-button { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 0.4rem 1rem; + gap: 1rem; + width: 4rem; + height: 2rem;; + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-size: 1rem; + line-height: 1.25rem; + letter-spacing: 0.0146491rem; + color: var(--white); + + margin: 0 auto; + width: 4rem; + height: 2rem;; + + background: var(--button-blue); + box-shadow: 0px 1rem 0.4rem rgba(38, 56, 84, 0.01), 0px 0.6rem 0.4rem rgba(38, 56, 84, 0.05), 0px 0.2rem 0.2rem rgba(38, 56, 84, 0.09), 0px 0.1rem 0.1rem rgba(38, 56, 84, 0.1); + border-radius: 1.25rem; + + flex: none; + order: 1; + flex-grow: 0; + } + + @media only screen and (min-width: 780px) { + + .option-icon-text { + font-size: 1.375rem; + white-space: nowrap; + position: absolute; + left: -30%; + transform: translateX(-50%); + top: 450%; + transform: translateY(-50%); + } + .popup-footer { + display: flex; + justify-content: center; + align-items: center; + gap: 14.375rem; + } + .finish-button, .back-button { + width: 6.625rem; + height: 2.6875rem; + padding: var(--Spacing12) var(--Spacing36) var(--Spacing12) var(--Spacing36); + gap: 0.625rem; + border-radius: 1.25rem; + opacity: 1; + } + } + @media only screen and (max-width: 361px) { + .popup-footer { + display: flex; + justify-content: center; + align-items: center; + gap: 8.5rem; + margin-bottom: 1rem; + } + } +} \ No newline at end of file diff --git a/src/view/pages/statement/components/settings/statementSettingsCont.ts b/src/view/pages/statement/components/settings/statementSettingsCont.ts index c9416e85..7a01acad 100644 --- a/src/view/pages/statement/components/settings/statementSettingsCont.ts +++ b/src/view/pages/statement/components/settings/statementSettingsCont.ts @@ -1,10 +1,10 @@ import { - Statement, - NavObject, - Vote, - Evaluation, - StatementType, - Screen, + Statement, + NavObject, + Vote, + Evaluation, + StatementType, + Screen, } from "delib-npm"; // Helpers @@ -12,9 +12,9 @@ import { getVoters } from "@/controllers/db/vote/getVotes"; import { getEvaluations } from "@/controllers/db/evaluation/getEvaluation"; import { navigateToStatementTab } from "@/controllers/general/helpers"; import { - createStatement, - setStatementToDB, - updateStatement, + createStatement, + setStatementToDB, + updateStatement, } from "@/controllers/db/statements/setStatements"; import { defaultResultsSettings, @@ -25,73 +25,73 @@ import { NavigateFunction } from 'react-router-dom'; // Get users that voted on options in this statement export async function handleGetVoters( - parentId: string | undefined, - setVoters: React.Dispatch>, - setClicked: React.Dispatch> + parentId: string | undefined, + setVoters: React.Dispatch>, + setClicked: React.Dispatch> ) { - if (!parentId) return; - const voters = await getVoters(parentId); - setVoters(voters); - setClicked(true); + if (!parentId) return; + const voters = await getVoters(parentId); + setVoters(voters); + setClicked(true); } //Get users that did not vote on options in this statement export async function handleGetNonVoters( - parentId: string | undefined, - setNonVoters: React.Dispatch>, - setClicked: React.Dispatch> + parentId: string | undefined, + setNonVoters: React.Dispatch>, + setClicked: React.Dispatch> ) { - if (!parentId) return; + if (!parentId) return; - try { - const voters = await getVoters(parentId); + try { + const voters = await getVoters(parentId); - // Filter out users who haven't voted (those with no voter information) - const nonVoters = voters.filter((voter) => !voter.voter); + // Filter out users who haven't voted (those with no voter information) + const nonVoters = voters.filter((voter) => !voter.voter); - setNonVoters(nonVoters); + setNonVoters(nonVoters); - setClicked(true); - } catch (error) { - console.error("Error fetching non-voters:", error); - } + setClicked(true); + } catch (error) { + console.error("Error fetching non-voters:", error); + } } // Get users that evaluated on options in this statement export async function handleGetEvaluators( - parentId: string | undefined, - setEvaluators: React.Dispatch>, - setClicked: React.Dispatch> + parentId: string | undefined, + setEvaluators: React.Dispatch>, + setClicked: React.Dispatch> ) { - if (!parentId) return; - const evaluators = await getEvaluations(parentId); - setEvaluators(evaluators); - setClicked(true); + if (!parentId) return; + const evaluators = await getEvaluations(parentId); + setEvaluators(evaluators); + setClicked(true); } // Check if sub-page is checked in stored statement export function isSubPageChecked( - statement: Statement | undefined, - navObj: NavObject + statement: Statement | undefined, + navObj: NavObject ): boolean { - try { - //in case of a new statement - if (!statement) { - if (navObj.default === false) return false; - else return true; - } - - //in case of an existing statement - const { subScreens } = statement; - if (!subScreens) return true; - if (subScreens.includes(navObj.link)) return true; - - return false; - } catch (error) { - console.error(error); - - return true; - } + try { + //in case of a new statement + if (!statement) { + if (navObj.default === false) return false; + else return true; + } + + //in case of an existing statement + const { subScreens } = statement; + if (!subScreens) return true; + if (subScreens.includes(navObj.link)) return true; + + return false; + } catch (error) { + console.error(error); + + return true; + } } interface HandleSetStatementParams { @@ -102,143 +102,143 @@ interface HandleSetStatementParams { } export async function handleSetStatement({ - navigate, - statementId, - statement, - parentStatement, + navigate, + statementId, + statement, + parentStatement, }: HandleSetStatementParams) { - try { - // If statement title is empty, don't save - if (!statement.statement) return; - - const { - hasChildren, - resultsBy, - numberOfResults, - enableAddEvaluationOption, - enableAddVotingOption, - enhancedEvaluation, - showEvaluation, - subScreens, - membership, - } = getSetStatementData(statement); - - // If no statementId, user is on AddStatement page - if (!statementId) { - const newStatement = createStatement({ - text: statement.statement, - description: statement.description, - subScreens, - statementType: StatementType.question, - parentStatement: "top", - resultsBy, - numberOfResults, - hasChildren, - enableAddEvaluationOption, - enableAddVotingOption, - enhancedEvaluation, - showEvaluation, - membership, - }); - if (!newStatement) throw new Error("newStatement had error in creating"); - - await setStatementToDB({ - parentStatement: "top", - statement: newStatement, - addSubscription: true, - }); - navigateToStatementTab(newStatement, navigate); - - return; - } - - // If statementId, user is on Settings tab in statement page - else { - // update statement - if (!statement) throw new Error("statement is undefined"); - - const newStatement = updateStatement({ - statement, - text: statement.statement, - description: statement.description || "", - subScreens: subScreens, - statementType: StatementType.question, - resultsBy, - numberOfResults, - hasChildren, - enableAddEvaluationOption, - enableAddVotingOption, - enhancedEvaluation, - showEvaluation, - membership, - }); - if (!newStatement) throw new Error("newStatement had not been updated"); - - await setStatementToDB({ - parentStatement, - statement: newStatement, - addSubscription: true, - }); - navigateToStatementTab(newStatement, navigate); - - return; - } - } catch (error) { - console.error(error); - } + try { + // If statement title is empty, don't save + if (!statement.statement) return; + + const { + hasChildren, + resultsBy, + numberOfResults, + enableAddEvaluationOption, + enableAddVotingOption, + enhancedEvaluation, + showEvaluation, + subScreens, + membership, + } = getSetStatementData(statement); + + // If no statementId, user is on AddStatement page + if (!statementId) { + const newStatement = createStatement({ + text: statement.statement, + description: statement.description, + subScreens, + statementType: StatementType.question, + parentStatement: "top", + resultsBy, + numberOfResults, + hasChildren, + enableAddEvaluationOption, + enableAddVotingOption, + enhancedEvaluation, + showEvaluation, + membership, + }); + if (!newStatement) throw new Error("newStatement had error in creating"); + + await setStatementToDB({ + parentStatement: "top", + statement: newStatement, + addSubscription: true, + }); + navigateToStatementTab(newStatement, navigate); + + return; + } + + // If statementId, user is on Settings tab in statement page + else { + // update statement + if (!statement) throw new Error("statement is undefined"); + + const newStatement = updateStatement({ + statement, + text: statement.statement, + description: statement.description || "", + subScreens: subScreens, + statementType: StatementType.question, + resultsBy, + numberOfResults, + hasChildren, + enableAddEvaluationOption, + enableAddVotingOption, + enhancedEvaluation, + showEvaluation, + membership, + }); + if (!newStatement) throw new Error("newStatement had not been updated"); + + await setStatementToDB({ + parentStatement, + statement: newStatement, + addSubscription: true, + }); + navigateToStatementTab(newStatement, navigate); + + return; + } + } catch (error) { + console.error(error); + } } export const getStatementSettings = (statement: Statement) => { - const statementSettings = + const statementSettings = statement.statementSettings ?? defaultStatementSettings; - return { - enableAddEvaluationOption: Boolean( - statementSettings.enableAddEvaluationOption - ), - enableAddVotingOption: Boolean(statementSettings.enableAddVotingOption), - enhancedEvaluation: Boolean(statementSettings.enhancedEvaluation), - showEvaluation: Boolean(statementSettings.showEvaluation), - subScreens: statementSettings.subScreens ?? [], - inVotingGetOnlyResults: Boolean(statementSettings.inVotingGetOnlyResults), - enableSimilaritiesSearch: Boolean( - statementSettings.enableSimilaritiesSearch - ), - enableNavigationalElements: Boolean( - statementSettings.enableNavigationalElements - ), - }; + return { + enableAddEvaluationOption: Boolean( + statementSettings.enableAddEvaluationOption + ), + enableAddVotingOption: Boolean(statementSettings.enableAddVotingOption), + enhancedEvaluation: Boolean(statementSettings.enhancedEvaluation), + showEvaluation: Boolean(statementSettings.showEvaluation), + subScreens: statementSettings.subScreens ?? [], + inVotingGetOnlyResults: Boolean(statementSettings.inVotingGetOnlyResults), + enableSimilaritiesSearch: Boolean( + statementSettings.enableSimilaritiesSearch + ), + enableNavigationalElements: Boolean( + statementSettings.enableNavigationalElements + ), + }; }; const getStatementSubScreens = (statement: Statement) => { - const defaultSubScreens = [Screen.CHAT, Screen.OPTIONS]; - const subScreens = statement.subScreens ?? defaultSubScreens; + const defaultSubScreens = [Screen.CHAT, Screen.OPTIONS]; + const subScreens = statement.subScreens ?? defaultSubScreens; - // don't allow setting sub-screens as an empty array - return subScreens.length === 0 ? defaultSubScreens : subScreens; + // don't allow setting sub-screens as an empty array + return subScreens.length === 0 ? defaultSubScreens : subScreens; }; const getSetStatementData = (statement: Statement) => { - const { resultsBy, numberOfResults } = + const { resultsBy, numberOfResults } = statement.resultsSettings ?? defaultResultsSettings; - const { - enableAddEvaluationOption, - enableAddVotingOption, - enhancedEvaluation, - showEvaluation, - } = getStatementSettings(statement); - - return { - hasChildren: Boolean(statement.hasChildren), - subScreens: getStatementSubScreens(statement), - resultsBy, - numberOfResults, - enableAddEvaluationOption, - enableAddVotingOption, - enhancedEvaluation, - showEvaluation, - membership: statement.membership, - }; + const { + enableAddEvaluationOption, + enableAddVotingOption, + enhancedEvaluation, + showEvaluation, + } = getStatementSettings(statement); + + return { + hasChildren: Boolean(statement.hasChildren), + subScreens: getStatementSubScreens(statement), + resultsBy, + numberOfResults, + enableAddEvaluationOption, + enableAddVotingOption, + enhancedEvaluation, + showEvaluation, + membership: statement.membership, + }; }; interface ToggleSubScreenParams { @@ -248,19 +248,19 @@ interface ToggleSubScreenParams { } export const toggleSubScreen = ({ - subScreens, - screenLink, - statement, + subScreens, + screenLink, + statement, }: ToggleSubScreenParams): Statement => { - const checked = subScreens.includes(screenLink) ?? false; - const newSubScreens = checked - ? subScreens.filter((subScreen) => subScreen !== screenLink) - : [...subScreens, screenLink]; - - return { - ...statement, - subScreens: newSubScreens, - }; + const checked = subScreens.includes(screenLink) ?? false; + const newSubScreens = checked + ? subScreens.filter((subScreen) => subScreen !== screenLink) + : [...subScreens, screenLink]; + + return { + ...statement, + subScreens: newSubScreens, + }; }; interface CreateStatementFromModalParams { @@ -279,28 +279,28 @@ export async function createStatementFromModal({ toggleAskNotifications, parentStatement }: CreateStatementFromModalParams) { - try { - if (!title) throw new Error("title is undefined"); - - const newStatement = createStatement({ - ...defaultStatementSettings, - hasChildren: true, - toggleAskNotifications, - text: title, - description, - parentStatement, - statementType: isOptionSelected - ? StatementType.option - : StatementType.question, - }); - - if (!newStatement) throw new Error("newStatement was not created"); - - await setStatementToDB({ - statement: newStatement, - parentStatement: parentStatement === "top" ? undefined : parentStatement, - addSubscription: true, - }); + try { + if (!title) throw new Error("title is undefined"); + + const newStatement = createStatement({ + ...defaultStatementSettings, + hasChildren: true, + toggleAskNotifications, + text: title, + description, + parentStatement, + statementType: isOptionSelected + ? StatementType.option + : StatementType.question, + }); + + if (!newStatement) throw new Error("newStatement was not created"); + + await setStatementToDB({ + statement: newStatement, + parentStatement: parentStatement === "top" ? undefined : parentStatement, + addSubscription: true, + }); await setStatementToDB({ statement: newStatement,