From 1b436d2dc6e125e63e036ee067d3faa284c24da3 Mon Sep 17 00:00:00 2001 From: sosokker Date: Thu, 9 Nov 2023 23:52:33 +0700 Subject: [PATCH 001/120] Add RecurrenceTaskViewSet --- backend/tasks/tasks/views.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/tasks/tasks/views.py b/backend/tasks/tasks/views.py index d884bbe..16f014c 100644 --- a/backend/tasks/tasks/views.py +++ b/backend/tasks/tasks/views.py @@ -1,6 +1,6 @@ from rest_framework import viewsets from rest_framework.permissions import IsAuthenticated -from tasks.models import Todo +from tasks.models import Todo, RecurrenceTask from .serializers import TaskCreateSerializer, TaskGeneralSerializer @@ -13,4 +13,10 @@ class TodoViewSet(viewsets.ModelViewSet): # Can't add ManytoMany at creation time (Tags) if self.action == 'create': return TaskCreateSerializer - return TaskGeneralSerializer \ No newline at end of file + return TaskGeneralSerializer + + +class RecurrenceTaskViewSet(viewsets.ModelViewSet): + queryset = Todo.objects.all() + serializer_class = TaskGeneralSerializer + permission_classes = [IsAuthenticated] \ No newline at end of file From bac1f96ad8f941356cfcaf5b01f8e64deb517a66 Mon Sep 17 00:00:00 2001 From: sosokker Date: Mon, 13 Nov 2023 23:46:52 +0700 Subject: [PATCH 002/120] Add Redirect Router if not authen --- frontend/src/App.jsx | 41 +++++++++++-------- frontend/src/PrivateRoute.jsx | 10 +++++ frontend/src/api/configs/AxiosConfig.jsx | 3 +- .../authentication/IsAuthenticated.jsx | 19 --------- .../src/components/navigations/Navbar.jsx | 2 +- .../hooks/authentication/IsAuthenticated.jsx | 25 +++++++++++ frontend/src/main.jsx | 14 ++++--- 7 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 frontend/src/PrivateRoute.jsx delete mode 100644 frontend/src/components/authentication/IsAuthenticated.jsx create mode 100644 frontend/src/hooks/authentication/IsAuthenticated.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 78f312c..6a3468f 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -11,6 +11,7 @@ import Calendar from "./components/calendar/calendar"; import KanbanBoard from "./components/kanbanBoard/kanbanBoard"; import IconSideNav from "./components/navigations/IconSideNav"; import Eisenhower from "./components/eisenhowerMatrix/Eisenhower"; +import PrivateRoute from "./PrivateRoute"; const App = () => { const location = useLocation(); @@ -18,24 +19,32 @@ const App = () => { const isLoginPageOrSignUpPage = prevention.some(_ => location.pathname.includes(_)); return ( -
- {!isLoginPageOrSignUpPage && } -
- -
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
+
+ {!isLoginPageOrSignUpPage && } +
+ +
+ + } /> + }> + } /> + + } /> + }> + } /> + + }> + } /> + + }> + } /> + + } /> + } /> +
+
); }; diff --git a/frontend/src/PrivateRoute.jsx b/frontend/src/PrivateRoute.jsx new file mode 100644 index 0000000..936a7d9 --- /dev/null +++ b/frontend/src/PrivateRoute.jsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { Navigate, Outlet } from 'react-router-dom'; +import IsAuthenticated from './hooks/authentication/IsAuthenticated'; + +const PrivateRoute = () => { + const auth = IsAuthenticated(); + return auth ? : ; +} + +export default PrivateRoute; \ No newline at end of file diff --git a/frontend/src/api/configs/AxiosConfig.jsx b/frontend/src/api/configs/AxiosConfig.jsx index 80015ac..a6469ae 100644 --- a/frontend/src/api/configs/AxiosConfig.jsx +++ b/frontend/src/api/configs/AxiosConfig.jsx @@ -1,4 +1,5 @@ import axios from 'axios'; +import { redirect } from 'react-router-dom'; const axiosInstance = axios.create({ baseURL: 'http://127.0.0.1:8000/api/', @@ -16,7 +17,7 @@ axiosInstance.interceptors.response.use( error => { const originalRequest = error.config; const refresh_token = localStorage.getItem('refresh_token'); - + // Check if the error is due to 401 and a refresh token is available if (error.response.status === 401 && error.response.statusText === "Unauthorized" && refresh_token !== "undefined") { return axiosInstance diff --git a/frontend/src/components/authentication/IsAuthenticated.jsx b/frontend/src/components/authentication/IsAuthenticated.jsx deleted file mode 100644 index 48322de..0000000 --- a/frontend/src/components/authentication/IsAuthenticated.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useState, useEffect } from 'react'; - -function IsAuthenticated() { - const [isAuthenticated, setIsAuthenticated] = useState(false); - - useEffect(() => { - const access_token = localStorage.getItem('access_token'); - - if (access_token) { - setIsAuthenticated(true); - } else { - setIsAuthenticated(false); - } - }, []); - - return isAuthenticated; -} - -export default IsAuthenticated; \ No newline at end of file diff --git a/frontend/src/components/navigations/Navbar.jsx b/frontend/src/components/navigations/Navbar.jsx index 75cd8a7..9328e1c 100644 --- a/frontend/src/components/navigations/Navbar.jsx +++ b/frontend/src/components/navigations/Navbar.jsx @@ -1,6 +1,6 @@ import * as React from "react"; import { useNavigate } from "react-router-dom"; -import IsAuthenticated from "../authentication/IsAuthenticated"; +import IsAuthenticated from "../../hooks/authentication/IsAuthenticated"; import axiosapi from "../../api/AuthenticationApi"; const settings = { diff --git a/frontend/src/hooks/authentication/IsAuthenticated.jsx b/frontend/src/hooks/authentication/IsAuthenticated.jsx new file mode 100644 index 0000000..a132fb2 --- /dev/null +++ b/frontend/src/hooks/authentication/IsAuthenticated.jsx @@ -0,0 +1,25 @@ +import { useEffect, useState } from 'react'; + +function IsAuthenticated() { + const [isAuthenticated, setIsAuthenticated] = useState(() => { + const access_token = localStorage.getItem('access_token'); + return !!access_token; + }); + + useEffect(() => { + const handleTokenChange = () => { + const newAccessToken = localStorage.getItem('access_token'); + setIsAuthenticated(!!newAccessToken); + }; + + window.addEventListener('storage', handleTokenChange); + + return () => { + window.removeEventListener('storage', handleTokenChange); + }; + }, []); + + return isAuthenticated; +} + +export default IsAuthenticated; diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index f5430b9..262782a 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -1,15 +1,17 @@ -import React from "react"; +import React, { Fragment } from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; -import { GoogleOAuthProvider} from '@react-oauth/google'; -import { BrowserRouter } from 'react-router-dom'; +import { GoogleOAuthProvider } from "@react-oauth/google"; +import { BrowserRouter } from "react-router-dom"; -const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID +const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID; ReactDOM.createRoot(document.getElementById("root")).render( - + + + -); \ No newline at end of file +); From 038a0c84b77277b63eda0056bc999b6964abb1c9 Mon Sep 17 00:00:00 2001 From: sosokker Date: Mon, 13 Nov 2023 23:51:17 +0700 Subject: [PATCH 003/120] Format code with Prettier --- frontend/src/App.css | 2 +- frontend/src/PrivateRoute.jsx | 14 +- frontend/src/api/UserProfileApi.jsx | 12 +- frontend/src/api/configs/AxiosConfig.jsx | 62 ++++---- .../EisenhowerMatrix/Eisenhower.jsx | 10 +- frontend/src/components/Home.jsx | 2 +- frontend/src/components/ProfileUpdatePage.jsx | 31 ++-- .../components/authentication/SignUpPage.jsx | 140 +++++++++--------- .../authentication/refreshAcessToken.jsx | 12 +- .../components/calendar/TaskDataHandler.jsx | 38 ++--- frontend/src/components/calendar/calendar.jsx | 8 +- frontend/src/components/icons/plusIcon.jsx | 11 +- frontend/src/components/icons/trashIcon.jsx | 32 ++-- .../kanbanBoard/columnContainer.jsx | 52 ++----- .../components/kanbanBoard/kanbanBoard.jsx | 67 +++------ .../src/components/kanbanBoard/taskCard.jsx | 28 +--- .../src/components/navigations/Navbar.jsx | 6 +- frontend/src/components/signup.jsx | 77 +++++----- frontend/src/components/testAuth.jsx | 67 +++++---- .../hooks/authentication/IsAuthenticated.jsx | 10 +- frontend/src/index.css | 14 +- 21 files changed, 310 insertions(+), 385 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index eaac616..48931c9 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -43,4 +43,4 @@ to { transform: rotate(360deg); } -} \ No newline at end of file +} diff --git a/frontend/src/PrivateRoute.jsx b/frontend/src/PrivateRoute.jsx index 936a7d9..600f7d4 100644 --- a/frontend/src/PrivateRoute.jsx +++ b/frontend/src/PrivateRoute.jsx @@ -1,10 +1,10 @@ -import React from 'react'; -import { Navigate, Outlet } from 'react-router-dom'; -import IsAuthenticated from './hooks/authentication/IsAuthenticated'; +import React from "react"; +import { Navigate, Outlet } from "react-router-dom"; +import IsAuthenticated from "./hooks/authentication/IsAuthenticated"; const PrivateRoute = () => { - const auth = IsAuthenticated(); - return auth ? : ; -} + const auth = IsAuthenticated(); + return auth ? : ; +}; -export default PrivateRoute; \ No newline at end of file +export default PrivateRoute; diff --git a/frontend/src/api/UserProfileApi.jsx b/frontend/src/api/UserProfileApi.jsx index ca80fd1..e7a1b17 100644 --- a/frontend/src/api/UserProfileApi.jsx +++ b/frontend/src/api/UserProfileApi.jsx @@ -1,11 +1,11 @@ -import axios from 'axios'; +import axios from "axios"; -const ApiUpdateUserProfile = async (formData) => { +const ApiUpdateUserProfile = async formData => { try { - const response = await axios.post('http://127.0.1:8000/api/user/update/', formData, { + const response = await axios.post("http://127.0.1:8000/api/user/update/", formData, { headers: { - 'Authorization': "Bearer " + localStorage.getItem('access_token'), - 'Content-Type': 'multipart/form-data', + Authorization: "Bearer " + localStorage.getItem("access_token"), + "Content-Type": "multipart/form-data", }, }); @@ -13,7 +13,7 @@ const ApiUpdateUserProfile = async (formData) => { return response.data; } catch (error) { - console.error('Error updating user profile:', error); + console.error("Error updating user profile:", error); throw error; } }; diff --git a/frontend/src/api/configs/AxiosConfig.jsx b/frontend/src/api/configs/AxiosConfig.jsx index a6469ae..b0410d1 100644 --- a/frontend/src/api/configs/AxiosConfig.jsx +++ b/frontend/src/api/configs/AxiosConfig.jsx @@ -1,43 +1,45 @@ -import axios from 'axios'; -import { redirect } from 'react-router-dom'; +import axios from "axios"; +import { redirect } from "react-router-dom"; const axiosInstance = axios.create({ - baseURL: 'http://127.0.0.1:8000/api/', - timeout: 5000, - headers: { - 'Authorization': "Bearer " + localStorage.getItem('access_token'), - 'Content-Type': 'application/json', - 'accept': 'application/json', - }, + baseURL: "http://127.0.0.1:8000/api/", + timeout: 5000, + headers: { + Authorization: "Bearer " + localStorage.getItem("access_token"), + "Content-Type": "application/json", + accept: "application/json", + }, }); // handling token refresh on 401 Unauthorized errors axiosInstance.interceptors.response.use( - response => response, - error => { - const originalRequest = error.config; - const refresh_token = localStorage.getItem('refresh_token'); - - // Check if the error is due to 401 and a refresh token is available - if (error.response.status === 401 && error.response.statusText === "Unauthorized" && refresh_token !== "undefined") { - return axiosInstance - .post('/token/refresh/', { refresh: refresh_token }) - .then((response) => { + response => response, + error => { + const originalRequest = error.config; + const refresh_token = localStorage.getItem("refresh_token"); - localStorage.setItem('access_token', response.data.access); + // Check if the error is due to 401 and a refresh token is available + if ( + error.response.status === 401 && + error.response.statusText === "Unauthorized" && + refresh_token !== "undefined" + ) { + return axiosInstance + .post("/token/refresh/", { refresh: refresh_token }) + .then(response => { + localStorage.setItem("access_token", response.data.access); - axiosInstance.defaults.headers['Authorization'] = "Bearer " + response.data.access; - originalRequest.headers['Authorization'] = "Bearer " + response.data.access; + axiosInstance.defaults.headers["Authorization"] = "Bearer " + response.data.access; + originalRequest.headers["Authorization"] = "Bearer " + response.data.access; - return axiosInstance(originalRequest); - }) - .catch(err => { - console.log('Interceptors error: ', err); - }); - } - return Promise.reject(error); + return axiosInstance(originalRequest); + }) + .catch(err => { + console.log("Interceptors error: ", err); + }); } + return Promise.reject(error); + } ); - export default axiosInstance; diff --git a/frontend/src/components/EisenhowerMatrix/Eisenhower.jsx b/frontend/src/components/EisenhowerMatrix/Eisenhower.jsx index 7800fa9..c300236 100644 --- a/frontend/src/components/EisenhowerMatrix/Eisenhower.jsx +++ b/frontend/src/components/EisenhowerMatrix/Eisenhower.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; function EachBlog({ name, colorCode }) { return ( @@ -6,18 +6,16 @@ function EachBlog({ name, colorCode }) {
{name}
-
- Content goes here -
+
Content goes here
); } function Eisenhower() { return ( -
+

The Eisenhower Matrix

-
+
diff --git a/frontend/src/components/Home.jsx b/frontend/src/components/Home.jsx index 3089df5..7fa7680 100644 --- a/frontend/src/components/Home.jsx +++ b/frontend/src/components/Home.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; function HomePage() { return ( diff --git a/frontend/src/components/ProfileUpdatePage.jsx b/frontend/src/components/ProfileUpdatePage.jsx index 06a0213..6985851 100644 --- a/frontend/src/components/ProfileUpdatePage.jsx +++ b/frontend/src/components/ProfileUpdatePage.jsx @@ -1,12 +1,12 @@ -import React, { useState, useRef } from 'react'; -import { ApiUpdateUserProfile } from '../api/UserProfileApi'; +import React, { useState, useRef } from "react"; +import { ApiUpdateUserProfile } from "../api/UserProfileApi"; function ProfileUpdate() { const [file, setFile] = useState(null); - const [username, setUsername] = useState(''); - const [fullName, setFullName] = useState(''); - const [about, setAbout] = useState(''); - const defaultImage = 'https://i1.sndcdn.com/artworks-cTz48e4f1lxn5Ozp-L3hopw-t500x500.jpg'; + const [username, setUsername] = useState(""); + const [fullName, setFullName] = useState(""); + const [about, setAbout] = useState(""); + const defaultImage = "https://i1.sndcdn.com/artworks-cTz48e4f1lxn5Ozp-L3hopw-t500x500.jpg"; const fileInputRef = useRef(null); const handleImageUpload = () => { @@ -15,7 +15,7 @@ function ProfileUpdate() { } }; - const handleFileChange = (e) => { + const handleFileChange = e => { const selectedFile = e.target.files[0]; if (selectedFile) { setFile(selectedFile); @@ -24,9 +24,9 @@ function ProfileUpdate() { const handleSave = () => { const formData = new FormData(); - formData.append('profile_pic', file); - formData.append('first_name', username); - formData.append('about', about); + formData.append("profile_pic", file); + formData.append("first_name", username); + formData.append("about", about); ApiUpdateUserProfile(formData); }; @@ -45,10 +45,7 @@ function ProfileUpdate() { ref={fileInputRef} /> -
+
{file ? ( Profile ) : ( @@ -69,7 +66,7 @@ function ProfileUpdate() { placeholder="Enter your username" className="input w-full" value={username} - onChange={(e) => setUsername(e.target.value)} + onChange={e => setUsername(e.target.value)} />
@@ -81,7 +78,7 @@ function ProfileUpdate() { placeholder="Enter your full name" className="input w-full" value={fullName} - onChange={(e) => setFullName(e.target.value)} + onChange={e => setFullName(e.target.value)} />
@@ -92,7 +89,7 @@ function ProfileUpdate() { placeholder="Tell us about yourself" className="textarea w-full h-32" value={about} - onChange={(e) => setAbout(e.target.value)} + onChange={e => setAbout(e.target.value)} />
diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 2712f97..28eb1c2 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -1,31 +1,30 @@ -import React, { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import axiosapi from '../../api/AuthenticationApi'; - -import Avatar from '@mui/material/Avatar'; -import Button from '@mui/material/Button'; -import CssBaseline from '@mui/material/CssBaseline'; -import TextField from '@mui/material/TextField'; -import FormControlLabel from '@mui/material/FormControlLabel'; -import Checkbox from '@mui/material/Checkbox'; -import Link from '@mui/material/Link'; -import Grid from '@mui/material/Grid'; -import Box from '@mui/material/Box'; -import LockOutlinedIcon from '@mui/icons-material/LockOutlined'; -import Typography from '@mui/material/Typography'; -import Container from '@mui/material/Container'; -import { createTheme, ThemeProvider } from '@mui/material/styles'; +import React, { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import axiosapi from "../../api/AuthenticationApi"; +import Avatar from "@mui/material/Avatar"; +import Button from "@mui/material/Button"; +import CssBaseline from "@mui/material/CssBaseline"; +import TextField from "@mui/material/TextField"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Checkbox from "@mui/material/Checkbox"; +import Link from "@mui/material/Link"; +import Grid from "@mui/material/Grid"; +import Box from "@mui/material/Box"; +import LockOutlinedIcon from "@mui/icons-material/LockOutlined"; +import Typography from "@mui/material/Typography"; +import Container from "@mui/material/Container"; +import { createTheme, ThemeProvider } from "@mui/material/styles"; function Copyright(props) { return ( - {'Copyright © '} + {"Copyright © "} TurTask - {' '} + {" "} {new Date().getFullYear()} - {'.'} + {"."} ); } @@ -33,37 +32,36 @@ function Copyright(props) { const defaultTheme = createTheme(); export default function SignUp() { + const Navigate = useNavigate(); - const Navigate = useNavigate(); + const [formData, setFormData] = useState({ + email: "", + username: "", + password: "", + }); + const [error, setError] = useState(null); + const [isSubmitting, setIsSubmitting] = useState(false); - const [formData, setFormData] = useState({ - email: '', - username: '', - password: '', - }); - const [error, setError] = useState(null); - const [isSubmitting, setIsSubmitting] = useState(false); - - const handleSubmit = async (e) => { - e.preventDefault(); - setIsSubmitting(true); - setError(null); - - try { - axiosapi.createUser(formData); - } catch (error) { - console.error('Error creating user:', error); - setError('Registration failed. Please try again.'); - } finally { - setIsSubmitting(false); - } - Navigate('/login'); - }; - - const handleChange = (e) => { - const { name, value } = e.target; - setFormData({ ...formData, [name]: value }); - }; + const handleSubmit = async e => { + e.preventDefault(); + setIsSubmitting(true); + setError(null); + + try { + axiosapi.createUser(formData); + } catch (error) { + console.error("Error creating user:", error); + setError("Registration failed. Please try again."); + } finally { + setIsSubmitting(false); + } + Navigate("/login"); + }; + + const handleChange = e => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; return ( @@ -71,13 +69,12 @@ export default function SignUp() { - + marginTop: 8, + display: "flex", + flexDirection: "column", + alignItems: "center", + }}> + @@ -85,17 +82,17 @@ export default function SignUp() { - - - + + + - @@ -148,4 +140,4 @@ export default function SignUp() { ); -} \ No newline at end of file +} diff --git a/frontend/src/components/authentication/refreshAcessToken.jsx b/frontend/src/components/authentication/refreshAcessToken.jsx index 89204d5..11a74fa 100644 --- a/frontend/src/components/authentication/refreshAcessToken.jsx +++ b/frontend/src/components/authentication/refreshAcessToken.jsx @@ -1,8 +1,8 @@ -import axios from 'axios'; +import axios from "axios"; async function refreshAccessToken() { - const refresh_token = localStorage.getItem('refresh_token'); - const access_token = localStorage.getItem('access_token'); + const refresh_token = localStorage.getItem("refresh_token"); + const access_token = localStorage.getItem("access_token"); if (access_token) { return true; @@ -12,7 +12,7 @@ async function refreshAccessToken() { return false; } - const refreshUrl = 'http://127.0.0.1:8000/api/token/refresh/'; + const refreshUrl = "http://127.0.0.1:8000/api/token/refresh/"; try { const response = await axios.post(refreshUrl, { refresh: refresh_token }); @@ -22,8 +22,8 @@ async function refreshAccessToken() { const newAccessToken = response.data.access; const newRefreshToken = response.data.refresh; - localStorage.setItem('access_token', newAccessToken); - localStorage.setItem('refresh_token', newRefreshToken); + localStorage.setItem("access_token", newAccessToken); + localStorage.setItem("refresh_token", newRefreshToken); return true; } else { diff --git a/frontend/src/components/calendar/TaskDataHandler.jsx b/frontend/src/components/calendar/TaskDataHandler.jsx index 3c123e9..933cb42 100644 --- a/frontend/src/components/calendar/TaskDataHandler.jsx +++ b/frontend/src/components/calendar/TaskDataHandler.jsx @@ -1,6 +1,6 @@ -import { fetchTodoTasks } from '../../api/TaskApi'; +import { fetchTodoTasks } from "../../api/TaskApi"; -let eventGuid = 0 +let eventGuid = 0; // function getDateAndTime(dateString) { // const dateObject = new Date(dateString); @@ -18,25 +18,25 @@ let eventGuid = 0 // return dateFormatted + timeFormatted; // } -const mapResponseToEvents = (response) => { - return response.map(item => ({ - id: createEventId(), - title: item.title, - start: item.start_event, - end: item.end_event, - })); -} +const mapResponseToEvents = response => { + return response.map(item => ({ + id: createEventId(), + title: item.title, + start: item.start_event, + end: item.end_event, + })); +}; export async function getEvents() { - try { - const response = await fetchTodoTasks(); - return mapResponseToEvents(response); - } catch (error) { - console.error(error); - return []; - } + try { + const response = await fetchTodoTasks(); + return mapResponseToEvents(response); + } catch (error) { + console.error(error); + return []; + } } export function createEventId() { - return String(eventGuid++); -} \ No newline at end of file + return String(eventGuid++); +} diff --git a/frontend/src/components/calendar/calendar.jsx b/frontend/src/components/calendar/calendar.jsx index 6258da9..f1f63e5 100644 --- a/frontend/src/components/calendar/calendar.jsx +++ b/frontend/src/components/calendar/calendar.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState } from "react"; import { formatDate } from "@fullcalendar/core"; import FullCalendar from "@fullcalendar/react"; import dayGridPlugin from "@fullcalendar/daygrid"; @@ -79,7 +79,7 @@ export default class Calendar extends React.Component { }); }; - handleDateSelect = (selectInfo) => { + handleDateSelect = selectInfo => { let title = prompt("Please enter a new title for your event"); let calendarApi = selectInfo.view.calendar; @@ -96,13 +96,13 @@ export default class Calendar extends React.Component { } }; - handleEventClick = (clickInfo) => { + handleEventClick = clickInfo => { if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) { clickInfo.event.remove(); } }; - handleEvents = (events) => { + handleEvents = events => { this.setState({ currentEvents: events, }); diff --git a/frontend/src/components/icons/plusIcon.jsx b/frontend/src/components/icons/plusIcon.jsx index 080d990..7363a7b 100644 --- a/frontend/src/components/icons/plusIcon.jsx +++ b/frontend/src/components/icons/plusIcon.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; function PlusIcon() { return ( @@ -8,13 +8,8 @@ function PlusIcon() { viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" - className="w-6 h-6" - > - + className="w-6 h-6"> + ); } diff --git a/frontend/src/components/icons/trashIcon.jsx b/frontend/src/components/icons/trashIcon.jsx index f0be9fc..c7721fd 100644 --- a/frontend/src/components/icons/trashIcon.jsx +++ b/frontend/src/components/icons/trashIcon.jsx @@ -1,22 +1,20 @@ -import React from 'react'; +import React from "react"; function TrashIcon() { - return ( - React.createElement( - "svg", - { - xmlns: "http://www.w3.org/2000/svg", - fill: "none", - viewBox: "0 0 24 24", - strokeWidth: 1.5, - className: "w-6 h-6" - }, - React.createElement("path", { - strokeLinecap: "round", - strokeLinejoin: "round", - d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" - }) - ) + return React.createElement( + "svg", + { + xmlns: "http://www.w3.org/2000/svg", + fill: "none", + viewBox: "0 0 24 24", + strokeWidth: 1.5, + className: "w-6 h-6", + }, + React.createElement("path", { + strokeLinecap: "round", + strokeLinejoin: "round", + d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0", + }) ); } diff --git a/frontend/src/components/kanbanBoard/columnContainer.jsx b/frontend/src/components/kanbanBoard/columnContainer.jsx index 5ff2333..102e424 100644 --- a/frontend/src/components/kanbanBoard/columnContainer.jsx +++ b/frontend/src/components/kanbanBoard/columnContainer.jsx @@ -5,29 +5,14 @@ import { useMemo, useState } from "react"; import PlusIcon from "../icons/plusIcon"; import TaskCard from "./taskCard"; -function ColumnContainer({ - column, - deleteColumn, - updateColumn, - createTask, - tasks, - deleteTask, - updateTask, -}) { +function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks, deleteTask, updateTask }) { const [editMode, setEditMode] = useState(false); const tasksIds = useMemo(() => { - return tasks.map((task) => task.id); + return tasks.map(task => task.id); }, [tasks]); - const { - setNodeRef, - attributes, - listeners, - transform, - transition, - isDragging, - } = useSortable({ + const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({ id: column.id, data: { type: "Column", @@ -57,8 +42,7 @@ function ColumnContainer({ rounded-md flex flex-col - " - >
+ ">
); } @@ -74,8 +58,7 @@ function ColumnContainer({ rounded-md flex flex-col - " - > + "> {/* Column title */}
+ ">
+ "> 0
{!editMode && column.title} @@ -119,12 +100,12 @@ function ColumnContainer({ updateColumn(column.id, e.target.value)} + onChange={e => updateColumn(column.id, e.target.value)} autoFocus onBlur={() => { setEditMode(false); }} - onKeyDown={(e) => { + onKeyDown={e => { if (e.key !== "Enter") return; setEditMode(false); }} @@ -142,8 +123,7 @@ function ColumnContainer({ rounded px-1 py-2 - " - > + ">
@@ -151,13 +131,8 @@ function ColumnContainer({ {/* Column task container */}
- {tasks.map((task) => ( - + {tasks.map(task => ( + ))}
@@ -166,8 +141,7 @@ function ColumnContainer({ className="flex gap-2 items-center border-columnBackgroundColor border-2 rounded-md p-4 border-x-columnBackgroundColor hover:bg-mainBackgroundColor hover:text-rose-500 active:bg-black" onClick={() => { createTask(column.id); - }} - > + }}> Add task diff --git a/frontend/src/components/kanbanBoard/kanbanBoard.jsx b/frontend/src/components/kanbanBoard/kanbanBoard.jsx index 1ec76b5..743d8a9 100644 --- a/frontend/src/components/kanbanBoard/kanbanBoard.jsx +++ b/frontend/src/components/kanbanBoard/kanbanBoard.jsx @@ -1,13 +1,7 @@ -import PlusIcon from "../icons/plusIcon" +import PlusIcon from "../icons/plusIcon"; import { useMemo, useState } from "react"; import ColumnContainer from "./columnContainer"; -import { - DndContext, - DragOverlay, - PointerSensor, - useSensor, - useSensors, -} from "@dnd-kit/core"; +import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from "@dnd-kit/core"; import { SortableContext, arrayMove } from "@dnd-kit/sortable"; import { createPortal } from "react-dom"; import TaskCard from "./taskCard"; @@ -98,7 +92,7 @@ const defaultTasks = [ function KanbanBoard() { const [columns, setColumns] = useState(defaultCols); - const columnsId = useMemo(() => columns.map((col) => col.id), [columns]); + const columnsId = useMemo(() => columns.map(col => col.id), [columns]); const [tasks, setTasks] = useState(defaultTasks); @@ -123,18 +117,12 @@ function KanbanBoard() { items-center overflow-x-auto overflow-y-hidden - " - > - + "> +
- {columns.map((col) => ( + {columns.map(col => ( task.columnId === col.id)} + tasks={tasks.filter(task => task.columnId === col.id)} /> ))} @@ -166,8 +154,7 @@ function KanbanBoard() { hover:ring-2 flex gap-2 - " - > + "> Add Column @@ -183,18 +170,10 @@ function KanbanBoard() { createTask={createTask} deleteTask={deleteTask} updateTask={updateTask} - tasks={tasks.filter( - (task) => task.columnId === activeColumn.id - )} - /> - )} - {activeTask && ( - task.columnId === activeColumn.id)} /> )} + {activeTask && } , document.body )} @@ -213,12 +192,12 @@ function KanbanBoard() { } function deleteTask(id) { - const newTasks = tasks.filter((task) => task.id !== id); + const newTasks = tasks.filter(task => task.id !== id); setTasks(newTasks); } function updateTask(id, content) { - const newTasks = tasks.map((task) => { + const newTasks = tasks.map(task => { if (task.id !== id) return task; return { ...task, content }; }); @@ -236,15 +215,15 @@ function KanbanBoard() { } function deleteColumn(id) { - const filteredColumns = columns.filter((col) => col.id !== id); + const filteredColumns = columns.filter(col => col.id !== id); setColumns(filteredColumns); - const newTasks = tasks.filter((t) => t.columnId !== id); + const newTasks = tasks.filter(t => t.columnId !== id); setTasks(newTasks); } function updateColumn(id, title) { - const newColumns = columns.map((col) => { + const newColumns = columns.map(col => { if (col.id !== id) return col; return { ...col, title }; }); @@ -279,10 +258,10 @@ function KanbanBoard() { const isActiveAColumn = active.data.current?.type === "Column"; if (!isActiveAColumn) return; - setColumns((columns) => { - const activeColumnIndex = columns.findIndex((col) => col.id === activeId); + setColumns(columns => { + const activeColumnIndex = columns.findIndex(col => col.id === activeId); - const overColumnIndex = columns.findIndex((col) => col.id === overId); + const overColumnIndex = columns.findIndex(col => col.id === overId); return arrayMove(columns, activeColumnIndex, overColumnIndex); }); @@ -303,9 +282,9 @@ function KanbanBoard() { if (!isActiveATask) return; if (isActiveATask && isOverATask) { - setTasks((tasks) => { - const activeIndex = tasks.findIndex((t) => t.id === activeId); - const overIndex = tasks.findIndex((t) => t.id === overId); + setTasks(tasks => { + const activeIndex = tasks.findIndex(t => t.id === activeId); + const overIndex = tasks.findIndex(t => t.id === overId); if (tasks[activeIndex].columnId !== tasks[overIndex].columnId) { tasks[activeIndex].columnId = tasks[overIndex].columnId; @@ -319,8 +298,8 @@ function KanbanBoard() { const isOverAColumn = over.data.current?.type === "Column"; if (isActiveATask && isOverAColumn) { - setTasks((tasks) => { - const activeIndex = tasks.findIndex((t) => t.id === activeId); + setTasks(tasks => { + const activeIndex = tasks.findIndex(t => t.id === activeId); tasks[activeIndex].columnId = overId; return arrayMove(tasks, activeIndex, activeIndex); diff --git a/frontend/src/components/kanbanBoard/taskCard.jsx b/frontend/src/components/kanbanBoard/taskCard.jsx index c6fb391..9dcafa7 100644 --- a/frontend/src/components/kanbanBoard/taskCard.jsx +++ b/frontend/src/components/kanbanBoard/taskCard.jsx @@ -7,14 +7,7 @@ function TaskCard({ task, deleteTask, updateTask }) { const [mouseIsOver, setMouseIsOver] = useState(false); const [editMode, setEditMode] = useState(true); - const { - setNodeRef, - attributes, - listeners, - transform, - transition, - isDragging, - } = useSortable({ + const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({ id: task.id, data: { type: "Task", @@ -29,7 +22,7 @@ function TaskCard({ task, deleteTask, updateTask }) { }; const toggleEditMode = () => { - setEditMode((prev) => !prev); + setEditMode(prev => !prev); setMouseIsOver(false); }; @@ -53,8 +46,7 @@ function TaskCard({ task, deleteTask, updateTask }) { style={style} {...attributes} {...listeners} - className="bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-inset hover:ring-rose-500 cursor-grab relative" - > + className="bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-inset hover:ring-rose-500 cursor-grab relative"> +
+
+ +
+
+
+
+

Overall Statistics

+
+
+
+
+
+
+
+

Achievements

+
+
+
+
+
+
+
+

Friends

+
+
+
+
+
+ + + + {/* Modal */} + +
+
+ + + +
+
+
+ ); +} +export default ProfileUpdatePage; From 02c51a7defa0e9d48a0c6b706060ea138ede3aa8 Mon Sep 17 00:00:00 2001 From: sosokker Date: Thu, 16 Nov 2023 22:20:18 +0700 Subject: [PATCH 009/120] Use react-icons instead of svg icon --- frontend/src/components/icons/plusIcon.jsx | 17 --------------- frontend/src/components/icons/trashIcon.jsx | 21 ------------------- .../kanbanBoard/columnContainer.jsx | 8 +++---- .../components/kanbanBoard/kanbanBoard.jsx | 5 +++-- .../src/components/kanbanBoard/taskCard.jsx | 16 +++++++------- .../components/navigations/IconSideNav.jsx | 11 +++------- 6 files changed, 18 insertions(+), 60 deletions(-) delete mode 100644 frontend/src/components/icons/plusIcon.jsx delete mode 100644 frontend/src/components/icons/trashIcon.jsx diff --git a/frontend/src/components/icons/plusIcon.jsx b/frontend/src/components/icons/plusIcon.jsx deleted file mode 100644 index 7363a7b..0000000 --- a/frontend/src/components/icons/plusIcon.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react"; - -function PlusIcon() { - return ( - - - - ); -} - -export default PlusIcon; diff --git a/frontend/src/components/icons/trashIcon.jsx b/frontend/src/components/icons/trashIcon.jsx deleted file mode 100644 index c7721fd..0000000 --- a/frontend/src/components/icons/trashIcon.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from "react"; - -function TrashIcon() { - return React.createElement( - "svg", - { - xmlns: "http://www.w3.org/2000/svg", - fill: "none", - viewBox: "0 0 24 24", - strokeWidth: 1.5, - className: "w-6 h-6", - }, - React.createElement("path", { - strokeLinecap: "round", - strokeLinejoin: "round", - d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0", - }) - ); -} - -export default TrashIcon; diff --git a/frontend/src/components/kanbanBoard/columnContainer.jsx b/frontend/src/components/kanbanBoard/columnContainer.jsx index 102e424..aa09993 100644 --- a/frontend/src/components/kanbanBoard/columnContainer.jsx +++ b/frontend/src/components/kanbanBoard/columnContainer.jsx @@ -1,8 +1,8 @@ import { SortableContext, useSortable } from "@dnd-kit/sortable"; -import TrashIcon from "../icons/trashIcon"; +import { BsFillTrashFill } from "react-icons/bs" +import { AiOutlinePlusCircle } from "react-icons/ai" import { CSS } from "@dnd-kit/utilities"; import { useMemo, useState } from "react"; -import PlusIcon from "../icons/plusIcon"; import TaskCard from "./taskCard"; function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks, deleteTask, updateTask }) { @@ -124,7 +124,7 @@ function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks px-1 py-2 "> - +
@@ -142,7 +142,7 @@ function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks onClick={() => { createTask(column.id); }}> - + Add task
diff --git a/frontend/src/components/kanbanBoard/kanbanBoard.jsx b/frontend/src/components/kanbanBoard/kanbanBoard.jsx index 743d8a9..e9b5257 100644 --- a/frontend/src/components/kanbanBoard/kanbanBoard.jsx +++ b/frontend/src/components/kanbanBoard/kanbanBoard.jsx @@ -1,10 +1,11 @@ -import PlusIcon from "../icons/plusIcon"; import { useMemo, useState } from "react"; import ColumnContainer from "./columnContainer"; import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from "@dnd-kit/core"; import { SortableContext, arrayMove } from "@dnd-kit/sortable"; import { createPortal } from "react-dom"; import TaskCard from "./taskCard"; +import { AiOutlinePlusCircle } from "react-icons/ai" + const defaultCols = [ { @@ -155,7 +156,7 @@ function KanbanBoard() { flex gap-2 "> - + Add Column diff --git a/frontend/src/components/kanbanBoard/taskCard.jsx b/frontend/src/components/kanbanBoard/taskCard.jsx index 9dcafa7..026b335 100644 --- a/frontend/src/components/kanbanBoard/taskCard.jsx +++ b/frontend/src/components/kanbanBoard/taskCard.jsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import TrashIcon from "../icons/trashIcon"; +import { BsFillTrashFill } from "react-icons/bs" import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; @@ -33,7 +33,7 @@ function TaskCard({ task, deleteTask, updateTask }) { style={style} className=" opacity-30 - bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl border-2 border-rose-500 cursor-grab relative + bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl border-2 border-gray-400 cursor-grab relative " /> ); @@ -46,11 +46,11 @@ function TaskCard({ task, deleteTask, updateTask }) { style={style} {...attributes} {...listeners} - className="bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-inset hover:ring-rose-500 cursor-grab relative"> + className="bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-inset bg-zinc-400 ring-zinc-950 cursor-grab relative"> + + + {/* Difficulty, Challenge and Importance */} +
+
+ +
+ Easy + Normal + Hard + Very Hard + Devil +
+
+
+
+ +
+
+
+
+ +
+
+
+ + {/* Subtask */} +
+

+ + + Subtasks + +

+
+ + +
+
+
- +
-

Hello!

-

Press ESC key or click on ✕ button to close

); From 0962ff13306d5aa654ace0b76b91da11b9c3948b Mon Sep 17 00:00:00 2001 From: sosokker Date: Fri, 17 Nov 2023 23:07:42 +0700 Subject: [PATCH 019/120] Add checked and range handler --- .../kanbanBoard/taskDetailModal.jsx | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/kanbanBoard/taskDetailModal.jsx b/frontend/src/components/kanbanBoard/taskDetailModal.jsx index adbf7f5..7c2247a 100644 --- a/frontend/src/components/kanbanBoard/taskDetailModal.jsx +++ b/frontend/src/components/kanbanBoard/taskDetailModal.jsx @@ -1,9 +1,23 @@ -import React from "react"; +import React, { useState } from "react"; import { FaTasks, FaRegListAlt } from "react-icons/fa"; import { FaPlus } from "react-icons/fa6"; import { TbChecklist } from "react-icons/tb"; function TaskDetailModal() { + const [difficulty, setDifficulty] = useState(50); + const [isChallengeChecked, setChallengeChecked] = useState(true); + const [isImportantChecked, setImportantChecked] = useState(true); + + const handleChallengeChange = () => { + setChallengeChecked(!isChallengeChecked); + }; + + const handleImportantChange = () => { + setImportantChecked(!isImportantChecked); + }; + const handleDifficultyChange = event => { + setDifficulty(parseInt(event.target.value, 10)); + }; return ( @@ -64,7 +78,16 @@ function TaskDetailModal() { {/* Difficulty, Challenge and Importance */}
- +
Easy Normal @@ -73,19 +96,32 @@ function TaskDetailModal() { Devil
+ {/* Challenge Checkbox */}
+ + {/* Important Checkbox */}
From 8954bff35888c2eb8b0285c85a2b15c76b502f6c Mon Sep 17 00:00:00 2001 From: Wissarut Kanasub Date: Sat, 18 Nov 2023 10:56:18 +0700 Subject: [PATCH 020/120] add signup panel --- frontend/package.json | 3 ++ frontend/pnpm-lock.yaml | 42 +++++++++++++++++++++++ frontend/src/App.jsx | 2 ++ frontend/src/components/signup/Signup.jsx | 39 +++++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 frontend/src/components/signup/Signup.jsx diff --git a/frontend/package.json b/frontend/package.json index e03bc04..d850234 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,9 @@ "@dnd-kit/utilities": "^3.2.2", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", + "@fortawesome/fontawesome-svg-core": "^6.4.2", + "@fortawesome/free-brands-svg-icons": "^6.4.2", + "@fortawesome/react-fontawesome": "^0.2.0", "@fullcalendar/core": "^6.1.9", "@fullcalendar/daygrid": "^6.1.9", "@fullcalendar/interaction": "^6.1.9", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index acf0447..2bce532 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -23,6 +23,15 @@ dependencies: '@emotion/styled': specifier: ^11.11.0 version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.37)(react@18.2.0) + '@fortawesome/fontawesome-svg-core': + specifier: ^6.4.2 + version: 6.4.2 + '@fortawesome/free-brands-svg-icons': + specifier: ^6.4.2 + version: 6.4.2 + '@fortawesome/react-fontawesome': + specifier: ^0.2.0 + version: 0.2.0(@fortawesome/fontawesome-svg-core@6.4.2)(react@18.2.0) '@fullcalendar/core': specifier: ^6.1.9 version: 6.1.9 @@ -820,6 +829,39 @@ packages: resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} dev: false + /@fortawesome/fontawesome-common-types@6.4.2: + resolution: {integrity: sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==} + engines: {node: '>=6'} + requiresBuild: true + dev: false + + /@fortawesome/fontawesome-svg-core@6.4.2: + resolution: {integrity: sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + '@fortawesome/fontawesome-common-types': 6.4.2 + dev: false + + /@fortawesome/free-brands-svg-icons@6.4.2: + resolution: {integrity: sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + '@fortawesome/fontawesome-common-types': 6.4.2 + dev: false + + /@fortawesome/react-fontawesome@0.2.0(@fortawesome/fontawesome-svg-core@6.4.2)(react@18.2.0): + resolution: {integrity: sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==} + peerDependencies: + '@fortawesome/fontawesome-svg-core': ~1 || ~6 + react: '>=16.3' + dependencies: + '@fortawesome/fontawesome-svg-core': 6.4.2 + prop-types: 15.8.1 + react: 18.2.0 + dev: false + /@fullcalendar/core@6.1.9: resolution: {integrity: sha512-eeG+z9BWerdsU9Ac6j16rpYpPnE0wxtnEHiHrh/u/ADbGTR3hCOjCD9PxQOfhOTHbWOVs7JQunGcksSPu5WZBQ==} dependencies: diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index ad9dc97..c4b93eb 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -12,6 +12,7 @@ import IconSideNav from "./components/navigations/IconSideNav"; import Eisenhower from "./components/eisenhowerMatrix/Eisenhower"; import PrivateRoute from "./PrivateRoute"; import ProfileUpdatePage from "./components/profilePage"; +import Signup from "./components/signup/Signup"; const App = () => { @@ -43,6 +44,7 @@ const App = () => { } /> } /> +
diff --git a/frontend/src/components/signup/Signup.jsx b/frontend/src/components/signup/Signup.jsx new file mode 100644 index 0000000..3958feb --- /dev/null +++ b/frontend/src/components/signup/Signup.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faGoogle, faGithub } from '@fortawesome/free-brands-svg-icons'; + +function Signup() { + return ( +
+
+

Create your account

+

+ Start spending more time on your own table. +

+
+
+ +
+ +
+ +
+ +
+ +
+
+
+
+ ); +} + +export default Signup; From 9cd87e5180f16c626727170c33759e7c1291822c Mon Sep 17 00:00:00 2001 From: Wissarut Kanasub Date: Sat, 18 Nov 2023 10:57:41 +0700 Subject: [PATCH 021/120] delete signup-panel from app --- frontend/src/App.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index c4b93eb..ad9dc97 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -12,7 +12,6 @@ import IconSideNav from "./components/navigations/IconSideNav"; import Eisenhower from "./components/eisenhowerMatrix/Eisenhower"; import PrivateRoute from "./PrivateRoute"; import ProfileUpdatePage from "./components/profilePage"; -import Signup from "./components/signup/Signup"; const App = () => { @@ -44,7 +43,6 @@ const App = () => { } /> } /> - From 69ffa633071d2ace6735abdcb491a7c37d8746b9 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sat, 18 Nov 2023 21:27:07 +0700 Subject: [PATCH 022/120] Updated Kanban Board --- frontend/src/components/kanbanBoard/kanbanBoard.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/kanbanBoard/kanbanBoard.jsx b/frontend/src/components/kanbanBoard/kanbanBoard.jsx index 2ec2914..7866bbb 100644 --- a/frontend/src/components/kanbanBoard/kanbanBoard.jsx +++ b/frontend/src/components/kanbanBoard/kanbanBoard.jsx @@ -136,6 +136,7 @@ function KanbanBoard() { ))} + {/* create new column */}
OR
{/* Login with Google Button */} - {/* Forgot Password Link */} @@ -129,19 +135,6 @@ function LoginPage() { - {/* Right Section (Blurred Image Background) */} -
-
- -
- Text Overlay -
-
); } From e25a6b6d2490f9754ea6ae862fbbd0bed00b9407 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 10:33:54 +0700 Subject: [PATCH 025/120] Completed particle background --- frontend/index.html | 2 - frontend/package.json | 5 +- frontend/pnpm-lock.yaml | 327 +++++++++++++++++- frontend/src/assets/particles.json | 109 ------ .../components/authentication/LoginPage.jsx | 128 +++++-- 5 files changed, 427 insertions(+), 144 deletions(-) delete mode 100644 frontend/src/assets/particles.json diff --git a/frontend/index.html b/frontend/index.html index 54f2ddd..ced3ebb 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -8,9 +8,7 @@
-
- diff --git a/frontend/package.json b/frontend/package.json index 680e700..3001ce7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,13 +33,14 @@ "framer-motion": "^10.16.4", "gapi-script": "^1.2.0", "jwt-decode": "^4.0.0", - "particles.js": "^2.0.0", "react": "^18.2.0", "react-beautiful-dnd": "^13.1.1", "react-bootstrap": "^2.9.1", "react-dom": "^18.2.0", "react-icons": "^4.11.0", - "react-router-dom": "^6.18.0" + "react-router-dom": "^6.18.0", + "react-tsparticles": "^2.12.2", + "tsparticles": "^2.12.0" }, "devDependencies": { "@tailwindcss/typography": "^0.5.10", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index d86fba2..b18f1f5 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -74,9 +74,6 @@ dependencies: jwt-decode: specifier: ^4.0.0 version: 4.0.0 - particles.js: - specifier: ^2.0.0 - version: 2.0.0 react: specifier: ^18.2.0 version: 18.2.0 @@ -95,6 +92,12 @@ dependencies: react-router-dom: specifier: ^6.18.0 version: 6.19.0(react-dom@18.2.0)(react@18.2.0) + react-tsparticles: + specifier: ^2.12.2 + version: 2.12.2(react@18.2.0) + tsparticles: + specifier: ^2.12.0 + version: 2.12.0 devDependencies: '@tailwindcss/typography': @@ -2928,10 +2931,6 @@ packages: lines-and-columns: 1.2.4 dev: false - /particles.js@2.0.0: - resolution: {integrity: sha512-8e0JIqkRbMMPlFBnF9f+92hX1s07jdkd3tqB8uHE9L+cwGGjIYjQM7QLgt0FQ5MZp6SFFYYDm/Y48pqK3ZvJOQ==} - dev: false - /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -3238,6 +3237,16 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-tsparticles@2.12.2(react@18.2.0): + resolution: {integrity: sha512-/nrEbyL8UROXKIMXe+f+LZN2ckvkwV2Qa+GGe/H26oEIc+wq/ybSG9REDwQiSt2OaDQGu0MwmA4BKmkL6wAWcA==} + requiresBuild: true + peerDependencies: + react: '>=16' + dependencies: + react: 18.2.0 + tsparticles-engine: 2.12.0 + dev: false + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -3571,6 +3580,310 @@ packages: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: false + /tsparticles-basic@2.12.0: + resolution: {integrity: sha512-pN6FBpL0UsIUXjYbiui5+IVsbIItbQGOlwyGV55g6IYJBgdTNXgFX0HRYZGE9ZZ9psEXqzqwLM37zvWnb5AG9g==} + dependencies: + tsparticles-engine: 2.12.0 + tsparticles-move-base: 2.12.0 + tsparticles-shape-circle: 2.12.0 + tsparticles-updater-color: 2.12.0 + tsparticles-updater-opacity: 2.12.0 + tsparticles-updater-out-modes: 2.12.0 + tsparticles-updater-size: 2.12.0 + dev: false + + /tsparticles-engine@2.12.0: + resolution: {integrity: sha512-ZjDIYex6jBJ4iMc9+z0uPe7SgBnmb6l+EJm83MPIsOny9lPpetMsnw/8YJ3xdxn8hV+S3myTpTN1CkOVmFv0QQ==} + requiresBuild: true + dev: false + + /tsparticles-interaction-external-attract@2.12.0: + resolution: {integrity: sha512-0roC6D1QkFqMVomcMlTaBrNVjVOpyNzxIUsjMfshk2wUZDAvTNTuWQdUpmsLS4EeSTDN3rzlGNnIuuUQqyBU5w==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-bounce@2.12.0: + resolution: {integrity: sha512-MMcqKLnQMJ30hubORtdq+4QMldQ3+gJu0bBYsQr9BsThsh8/V0xHc1iokZobqHYVP5tV77mbFBD8Z7iSCf0TMQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-bubble@2.12.0: + resolution: {integrity: sha512-5kImCSCZlLNccXOHPIi2Yn+rQWTX3sEa/xCHwXW19uHxtILVJlnAweayc8+Zgmb7mo0DscBtWVFXHPxrVPFDUA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-connect@2.12.0: + resolution: {integrity: sha512-ymzmFPXz6AaA1LAOL5Ihuy7YSQEW8MzuSJzbd0ES13U8XjiU3HlFqlH6WGT1KvXNw6WYoqrZt0T3fKxBW3/C3A==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-grab@2.12.0: + resolution: {integrity: sha512-iQF/A947hSfDNqAjr49PRjyQaeRkYgTYpfNmAf+EfME8RsbapeP/BSyF6mTy0UAFC0hK2A2Hwgw72eT78yhXeQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-pause@2.12.0: + resolution: {integrity: sha512-4SUikNpsFROHnRqniL+uX2E388YTtfRWqqqZxRhY0BrijH4z04Aii3YqaGhJxfrwDKkTQlIoM2GbFT552QZWjw==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-push@2.12.0: + resolution: {integrity: sha512-kqs3V0dgDKgMoeqbdg+cKH2F+DTrvfCMrPF1MCCUpBCqBiH+TRQpJNNC86EZYHfNUeeLuIM3ttWwIkk2hllR/Q==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-remove@2.12.0: + resolution: {integrity: sha512-2eNIrv4m1WB2VfSVj46V2L/J9hNEZnMgFc+A+qmy66C8KzDN1G8aJUAf1inW8JVc0lmo5+WKhzex4X0ZSMghBg==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-repulse@2.12.0: + resolution: {integrity: sha512-rSzdnmgljeBCj5FPp4AtGxOG9TmTsK3AjQW0vlyd1aG2O5kSqFjR+FuT7rfdSk9LEJGH5SjPFE6cwbuy51uEWA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-slow@2.12.0: + resolution: {integrity: sha512-2IKdMC3om7DttqyroMtO//xNdF0NvJL/Lx7LDo08VpfTgJJozxU+JAUT8XVT7urxhaDzbxSSIROc79epESROtA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-external-trail@2.12.0: + resolution: {integrity: sha512-LKSapU5sPTaZqYx+y5VJClj0prlV7bswplSFQaIW1raXkvsk45qir2AVcpP5JUhZSFSG+SwsHr+qCgXhNeN1KA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-particles-attract@2.12.0: + resolution: {integrity: sha512-Hl8qwuwF9aLq3FOkAW+Zomu7Gb8IKs6Y3tFQUQScDmrrSCaeRt2EGklAiwgxwgntmqzL7hbMWNx06CHHcUQKdQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-particles-collisions@2.12.0: + resolution: {integrity: sha512-Se9nPWlyPxdsnHgR6ap4YUImAu3W5MeGKJaQMiQpm1vW8lSMOUejI1n1ioIaQth9weKGKnD9rvcNn76sFlzGBA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-interaction-particles-links@2.12.0: + resolution: {integrity: sha512-e7I8gRs4rmKfcsHONXMkJnymRWpxHmeaJIo4g2NaDRjIgeb2AcJSWKWZvrsoLnm7zvaf/cMQlbN6vQwCixYq3A==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-move-base@2.12.0: + resolution: {integrity: sha512-oSogCDougIImq+iRtIFJD0YFArlorSi8IW3HD2gO3USkH+aNn3ZqZNTqp321uB08K34HpS263DTbhLHa/D6BWw==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-move-parallax@2.12.0: + resolution: {integrity: sha512-58CYXaX8Ih5rNtYhpnH0YwU4Ks7gVZMREGUJtmjhuYN+OFr9FVdF3oDIJ9N6gY5a5AnAKz8f5j5qpucoPRcYrQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-particles.js@2.12.0: + resolution: {integrity: sha512-LyOuvYdhbUScmA4iDgV3LxA0HzY1DnOwQUy3NrPYO393S2YwdDjdwMod6Btq7EBUjg9FVIh+sZRizgV5elV2dg==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-plugin-absorbers@2.12.0: + resolution: {integrity: sha512-2CkPreaXHrE5VzFlxUKLeRB5t66ff+3jwLJoDFgQcp+R4HOEITo0bBZv2DagGP0QZdYN4grpnQzRBVdB4d1rWA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-plugin-easing-quad@2.12.0: + resolution: {integrity: sha512-2mNqez5pydDewMIUWaUhY5cNQ80IUOYiujwG6qx9spTq1D6EEPLbRNAEL8/ecPdn2j1Um3iWSx6lo340rPkv4Q==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-plugin-emitters@2.12.0: + resolution: {integrity: sha512-fbskYnaXWXivBh9KFReVCfqHdhbNQSK2T+fq2qcGEWpwtDdgujcaS1k2Q/xjZnWNMfVesik4IrqspcL51gNdSA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-shape-circle@2.12.0: + resolution: {integrity: sha512-L6OngbAlbadG7b783x16ns3+SZ7i0SSB66M8xGa5/k+YcY7zm8zG0uPt1Hd+xQDR2aNA3RngVM10O23/Lwk65Q==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-shape-image@2.12.0: + resolution: {integrity: sha512-iCkSdUVa40DxhkkYjYuYHr9MJGVw+QnQuN5UC+e/yBgJQY+1tQL8UH0+YU/h0GHTzh5Sm+y+g51gOFxHt1dj7Q==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-shape-line@2.12.0: + resolution: {integrity: sha512-RcpKmmpKlk+R8mM5wA2v64Lv1jvXtU4SrBDv3vbdRodKbKaWGGzymzav1Q0hYyDyUZgplEK/a5ZwrfrOwmgYGA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-shape-polygon@2.12.0: + resolution: {integrity: sha512-5YEy7HVMt1Obxd/jnlsjajchAlYMr9eRZWN+lSjcFSH6Ibra7h59YuJVnwxOxAobpijGxsNiBX0PuGQnB47pmA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-shape-square@2.12.0: + resolution: {integrity: sha512-33vfajHqmlODKaUzyPI/aVhnAOT09V7nfEPNl8DD0cfiNikEuPkbFqgJezJuE55ebtVo7BZPDA9o7GYbWxQNuw==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-shape-star@2.12.0: + resolution: {integrity: sha512-4sfG/BBqm2qBnPLASl2L5aBfCx86cmZLXeh49Un+TIR1F5Qh4XUFsahgVOG0vkZQa+rOsZPEH04xY5feWmj90g==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-shape-text@2.12.0: + resolution: {integrity: sha512-v2/FCA+hyTbDqp2ymFOe97h/NFb2eezECMrdirHWew3E3qlvj9S/xBibjbpZva2gnXcasBwxn0+LxKbgGdP0rA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-slim@2.12.0: + resolution: {integrity: sha512-27w9aGAAAPKHvP4LHzWFpyqu7wKyulayyaZ/L6Tuuejy4KP4BBEB4rY5GG91yvAPsLtr6rwWAn3yS+uxnBDpkA==} + dependencies: + tsparticles-basic: 2.12.0 + tsparticles-engine: 2.12.0 + tsparticles-interaction-external-attract: 2.12.0 + tsparticles-interaction-external-bounce: 2.12.0 + tsparticles-interaction-external-bubble: 2.12.0 + tsparticles-interaction-external-connect: 2.12.0 + tsparticles-interaction-external-grab: 2.12.0 + tsparticles-interaction-external-pause: 2.12.0 + tsparticles-interaction-external-push: 2.12.0 + tsparticles-interaction-external-remove: 2.12.0 + tsparticles-interaction-external-repulse: 2.12.0 + tsparticles-interaction-external-slow: 2.12.0 + tsparticles-interaction-particles-attract: 2.12.0 + tsparticles-interaction-particles-collisions: 2.12.0 + tsparticles-interaction-particles-links: 2.12.0 + tsparticles-move-base: 2.12.0 + tsparticles-move-parallax: 2.12.0 + tsparticles-particles.js: 2.12.0 + tsparticles-plugin-easing-quad: 2.12.0 + tsparticles-shape-circle: 2.12.0 + tsparticles-shape-image: 2.12.0 + tsparticles-shape-line: 2.12.0 + tsparticles-shape-polygon: 2.12.0 + tsparticles-shape-square: 2.12.0 + tsparticles-shape-star: 2.12.0 + tsparticles-shape-text: 2.12.0 + tsparticles-updater-color: 2.12.0 + tsparticles-updater-life: 2.12.0 + tsparticles-updater-opacity: 2.12.0 + tsparticles-updater-out-modes: 2.12.0 + tsparticles-updater-rotate: 2.12.0 + tsparticles-updater-size: 2.12.0 + tsparticles-updater-stroke-color: 2.12.0 + dev: false + + /tsparticles-updater-color@2.12.0: + resolution: {integrity: sha512-KcG3a8zd0f8CTiOrylXGChBrjhKcchvDJjx9sp5qpwQK61JlNojNCU35xoaSk2eEHeOvFjh0o3CXWUmYPUcBTQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-destroy@2.12.0: + resolution: {integrity: sha512-6NN3dJhxACvzbIGL4dADbYQSZJmdHfwjujj1uvnxdMbb2x8C/AZzGxiN33smo4jkrZ5VLEWZWCJPJ8aOKjQ2Sg==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-life@2.12.0: + resolution: {integrity: sha512-J7RWGHAZkowBHpcLpmjKsxwnZZJ94oGEL2w+wvW1/+ZLmAiFFF6UgU0rHMC5CbHJT4IPx9cbkYMEHsBkcRJ0Bw==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-opacity@2.12.0: + resolution: {integrity: sha512-YUjMsgHdaYi4HN89LLogboYcCi1o9VGo21upoqxq19yRy0hRCtx2NhH22iHF/i5WrX6jqshN0iuiiNefC53CsA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-out-modes@2.12.0: + resolution: {integrity: sha512-owBp4Gk0JNlSrmp12XVEeBroDhLZU+Uq3szbWlHGSfcR88W4c/0bt0FiH5bHUqORIkw+m8O56hCjbqwj69kpOQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-roll@2.12.0: + resolution: {integrity: sha512-dxoxY5jP4C9x15BxlUv5/Q8OjUPBiE09ToXRyBxea9aEJ7/iMw6odvi1HuT0H1vTIfV7o1MYawjeCbMycvODKQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-rotate@2.12.0: + resolution: {integrity: sha512-waOFlGFmEZOzsQg4C4VSejNVXGf4dMf3fsnQrEROASGf1FCd8B6WcZau7JtXSTFw0OUGuk8UGz36ETWN72DkCw==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-size@2.12.0: + resolution: {integrity: sha512-B0yRdEDd/qZXCGDL/ussHfx5YJ9UhTqNvmS5X2rR2hiZhBAE2fmsXLeWkdtF2QusjPeEqFDxrkGiLOsh6poqRA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-stroke-color@2.12.0: + resolution: {integrity: sha512-MPou1ZDxsuVq6SN1fbX+aI5yrs6FyP2iPCqqttpNbWyL+R6fik1rL0ab/x02B57liDXqGKYomIbBQVP3zUTW1A==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-tilt@2.12.0: + resolution: {integrity: sha512-HDEFLXazE+Zw+kkKKAiv0Fs9D9sRP61DoCR6jZ36ipea6OBgY7V1Tifz2TSR1zoQkk57ER9+EOQbkSQO+YIPGQ==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-twinkle@2.12.0: + resolution: {integrity: sha512-JhK/DO4kTx7IFwMBP2EQY9hBaVVvFnGBvX21SQWcjkymmN1hZ+NdcgUtR9jr4jUiiSNdSl7INaBuGloVjWvOgA==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles-updater-wobble@2.12.0: + resolution: {integrity: sha512-85FIRl95ipD3jfIsQdDzcUC5PRMWIrCYqBq69nIy9P8rsNzygn+JK2n+P1VQZowWsZvk0mYjqb9OVQB21Lhf6Q==} + dependencies: + tsparticles-engine: 2.12.0 + dev: false + + /tsparticles@2.12.0: + resolution: {integrity: sha512-aw77llkaEhcKYUHuRlggA6SB1Dpa814/nrStp9USGiDo5QwE1Ckq30QAgdXU6GRvnblUFsiO750ZuLQs5Y0tVw==} + dependencies: + tsparticles-engine: 2.12.0 + tsparticles-interaction-external-trail: 2.12.0 + tsparticles-plugin-absorbers: 2.12.0 + tsparticles-plugin-emitters: 2.12.0 + tsparticles-slim: 2.12.0 + tsparticles-updater-destroy: 2.12.0 + tsparticles-updater-roll: 2.12.0 + tsparticles-updater-tilt: 2.12.0 + tsparticles-updater-twinkle: 2.12.0 + tsparticles-updater-wobble: 2.12.0 + dev: false + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} diff --git a/frontend/src/assets/particles.json b/frontend/src/assets/particles.json deleted file mode 100644 index b5e677d..0000000 --- a/frontend/src/assets/particles.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "particles": { - "number": { - "value": 50, - "density": { - "enable": true, - "value_area": 800 - } - }, - "color": { - "value": "#000" - }, - "shape": { - "type": "circle", - "stroke": { - "width": 0, - "color": "#000000" - }, - "polygon": { - "nb_sides": 5 - }, - "image": { - "src": "img/github.svg", - "width": 100, - "height": 100 - } - }, - "opacity": { - "value": 0.5, - "random": false, - "anim": { - "enable": false, - "speed": 1, - "opacity_min": 0.1, - "sync": false - } - }, - "size": { - "value": 10, - "random": true, - "anim": { - "enable": false, - "speed": 80, - "size_min": 0.1, - "sync": false - } - }, - "line_linked": { - "enable": true, - "distance": 150, - "color": "#000", - "opacity": 0.4, - "width": 2 - }, - "move": { - "enable": true, - "speed": 6, - "direction": "none", - "random": false, - "straight": false, - "out_mode": "out", - "bounce": false, - "attract": { - "enable": false, - "rotateX": 600, - "rotateY": 1200 - } - } - }, - "interactivity": { - "detect_on": "canvas", - "events": { - "onhover": { - "enable": true, - "mode": "repulse" - }, - "onclick": { - "enable": false, - "mode": "push" - }, - "resize": true - }, - "modes": { - "grab": { - "distance": 150, - "line_linked": { - "opacity": 1 - } - }, - "bubble": { - "distance": 800, - "size": 80, - "duration": 2, - "opacity": 0.8, - "speed": 3 - }, - "repulse": { - "distance": 400, - "duration": 0.4 - }, - "push": { - "particles_nb": 4 - }, - "remove": { - "particles_nb": 2 - } - } - } - } \ No newline at end of file diff --git a/frontend/src/components/authentication/LoginPage.jsx b/frontend/src/components/authentication/LoginPage.jsx index 1528e26..7626ef2 100644 --- a/frontend/src/components/authentication/LoginPage.jsx +++ b/frontend/src/components/authentication/LoginPage.jsx @@ -1,9 +1,12 @@ import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useGoogleLogin } from "@react-oauth/google"; +import { useCallback } from "react"; +import Particles from "react-tsparticles"; +import { loadFull } from "tsparticles"; import refreshAccessToken from "./refreshAcesstoken"; import axiosapi from "../../api/AuthenticationApi"; -import { useAuth } from "../../hooks/authentication/IsAuthenticated"; +import { useAuth } from "../../hooks/authentication/IsAuthenticated"; function LoginPage() { const Navigate = useNavigate(); @@ -18,15 +21,14 @@ function LoginPage() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); - const handleEmailChange = event => { + const handleEmailChange = (event) => { setEmail(event.target.value); }; - const handlePasswordChange = event => { + const handlePasswordChange = (event) => { setPassword(event.target.value); }; - - const handleSubmit = event => { + const handleSubmit = (event) => { event.preventDefault(); // Send a POST request to the authentication API @@ -35,15 +37,16 @@ function LoginPage() { email: email, password: password, }) - .then(res => { + .then((res) => { // On successful login, store tokens and set the authorization header localStorage.setItem("access_token", res.data.access); localStorage.setItem("refresh_token", res.data.refresh); - axiosapi.axiosInstance.defaults.headers["Authorization"] = "Bearer " + res.data.access; + axiosapi.axiosInstance.defaults.headers["Authorization"] = + "Bearer " + res.data.access; setIsAuthenticated(true); Navigate("/"); }) - .catch(err => { + .catch((err) => { console.log("Login failed"); console.log(err); setIsAuthenticated(false); @@ -53,7 +56,7 @@ function LoginPage() { const googleLoginImplicit = useGoogleLogin({ flow: "auth-code", redirect_uri: "postmessage", - onSuccess: async response => { + onSuccess: async (response) => { try { const loginResponse = await axiosapi.googleLogin(response.code); if (loginResponse && loginResponse.data) { @@ -69,23 +72,99 @@ function LoginPage() { setIsAuthenticated(false); } }, - onError: errorResponse => console.log(errorResponse), + onError: (errorResponse) => console.log(errorResponse), }); - useEffect(() => { - // Load particles.js configuration - particlesJS.load('particles-js', 'src/assets/particles.json', function() { - console.log('callback - particles.js config loaded'); - }); + const particlesInit = useCallback(async (engine) => { + console.log(engine); + await loadFull(engine); }, []); + const particlesLoaded = useCallback(async (container) => { + console.log(container); + }, []); return ( -
-
- {/* Left Section (Login Box) */} -
-
-

Log in to your account

+
+ {/* Particles Container */} +
+ +
+ {/* Login Box */} +
+
+

Login

{/* Email Input */}
@@ -123,7 +201,10 @@ function LoginPage() {
OR
{/* Login with Google Button */} - {/* Forgot Password Link */} @@ -134,7 +215,6 @@ function LoginPage() {
-
); } From 9e43ca4ce3b8a03129ae35a9026d06c84d00f8b6 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 10:44:12 +0700 Subject: [PATCH 026/120] Completed login page improvement. --- frontend/src/components/authentication/LoginPage.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/authentication/LoginPage.jsx b/frontend/src/components/authentication/LoginPage.jsx index 7626ef2..f946686 100644 --- a/frontend/src/components/authentication/LoginPage.jsx +++ b/frontend/src/components/authentication/LoginPage.jsx @@ -124,7 +124,7 @@ function LoginPage() { value: "#008000", }, links: { - color: "#ffffff", + color: "#00ff00", distance: 150, enable: true, opacity: 0.1, @@ -164,7 +164,7 @@ function LoginPage() { {/* Login Box */}
-

Login

+

Login

{/* Email Input */}
{/* Login Button */} -
OR
From 5aa46a8553f3667a868bf53954970f917de8fdf8 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 10:45:03 +0700 Subject: [PATCH 027/120] Completed login page improvement. --- frontend/src/components/authentication/LoginPage.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/components/authentication/LoginPage.jsx b/frontend/src/components/authentication/LoginPage.jsx index f946686..12ad18e 100644 --- a/frontend/src/components/authentication/LoginPage.jsx +++ b/frontend/src/components/authentication/LoginPage.jsx @@ -74,6 +74,9 @@ function LoginPage() { }, onError: (errorResponse) => console.log(errorResponse), }); + { + /* Particles Loader*/ + } const particlesInit = useCallback(async (engine) => { console.log(engine); await loadFull(engine); From 146cc6dcdeaeeb22525f0c16beceb2d7ebb2d666 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 17:49:31 +0700 Subject: [PATCH 028/120] Installing necessary modules for dashboard. --- frontend/package.json | 1 + frontend/pnpm-lock.yaml | 406 +++++++++++++++++++++++++++++------- frontend/tailwind.config.js | 98 ++++++++- 3 files changed, 423 insertions(+), 82 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 3001ce7..c2ac047 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,6 +27,7 @@ "@react-oauth/google": "^0.11.1", "@syncfusion/ej2-base": "^23.1.41", "@syncfusion/ej2-kanban": "^23.1.36", + "@tremor/react": "^3.11.1", "axios": "^1.6.1", "bootstrap": "^5.3.2", "dotenv": "^16.3.1", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index b18f1f5..71f96fe 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -56,6 +56,9 @@ dependencies: '@syncfusion/ej2-kanban': specifier: ^23.1.36 version: 23.1.36 + '@tremor/react': + specifier: ^3.11.1 + version: 3.11.1(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0)(tailwindcss@3.3.5) axios: specifier: ^1.6.1 version: 1.6.2 @@ -150,7 +153,6 @@ packages: /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - dev: true /@ampproject/remapping@2.2.1: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} @@ -811,6 +813,17 @@ packages: '@floating-ui/utils': 0.1.6 dev: false + /@floating-ui/react-dom@1.3.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.5.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@floating-ui/react-dom@2.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==} peerDependencies: @@ -822,6 +835,19 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@floating-ui/react@0.19.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-JyNk4A0Ezirq8FlXECvRtQOX/iBe5Ize0W/pLkrZjfHW9GUV7Xnq6zm6fyZuQzaHHqEnVizmvlA96e1/CkZv+w==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/react-dom': 1.3.0(react-dom@18.2.0)(react@18.2.0) + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tabbable: 6.2.0 + dev: false + /@floating-ui/utils@0.1.6: resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} dev: false @@ -869,6 +895,27 @@ packages: '@fullcalendar/daygrid': 6.1.9(@fullcalendar/core@6.1.9) dev: false + /@headlessui/react@1.7.17(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-4am+tzvkqDSSgiwrsEpGWqgGo9dz8qU5M3znCkC4PgkpY4HcCZzEDEvozltGGGHIKl9jbXbZPSH5TWn4sWJdow==} + engines: {node: '>=10'} + peerDependencies: + react: ^16 || ^17 || ^18 + react-dom: ^16 || ^17 || ^18 + dependencies: + client-only: 0.0.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@headlessui/tailwindcss@0.1.3(tailwindcss@3.3.5): + resolution: {integrity: sha512-3aMdDyYZx9A15euRehpppSyQnb2gIw2s/Uccn2ELIoLQ9oDy0+9oRygNWNjXCD5Dt+w1pxo7C+XoiYvGcqA4Kg==} + engines: {node: '>=10'} + peerDependencies: + tailwindcss: ^3.0 + dependencies: + tailwindcss: 3.3.5 + dev: false + /@humanwhocodes/config-array@0.11.13: resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} @@ -896,28 +943,23 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.20 - dev: true /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true /@jridgewell/trace-mapping@0.3.20: resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true /@mui/base@5.0.0-beta.24(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-bKt2pUADHGQtqWDZ8nvL2Lvg2GNJyd/ZUgZAJoYzRgmnxBL9j36MSlS3+exEdYkikcnvVafcBtD904RypFKb0w==} @@ -1103,12 +1145,10 @@ packages: dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - dev: true /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} @@ -1116,7 +1156,6 @@ packages: dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 - dev: true /@popperjs/core@2.11.8: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} @@ -1298,6 +1337,27 @@ packages: tailwindcss: 3.3.5 dev: true + /@tremor/react@3.11.1(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0)(tailwindcss@3.3.5): + resolution: {integrity: sha512-oiBm8vFe0+05RFIHlriSmfZX7BMwgAIFGdvz5kAEbN6G/cGOh2oPkTGG+NPbbk8eyo68f13IT6KfTiMVSEhRSA==} + peerDependencies: + react: ^18.0.0 + react-dom: '>=16.6.0' + dependencies: + '@floating-ui/react': 0.19.2(react-dom@18.2.0)(react@18.2.0) + '@headlessui/react': 1.7.17(react-dom@18.2.0)(react@18.2.0) + '@headlessui/tailwindcss': 0.1.3(tailwindcss@3.3.5) + date-fns: 2.30.0 + react: 18.2.0 + react-day-picker: 8.9.1(date-fns@2.30.0)(react@18.2.0) + react-dom: 18.2.0(react@18.2.0) + react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) + recharts: 2.9.3(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) + tailwind-merge: 1.14.0 + transitivePeerDependencies: + - prop-types + - tailwindcss + dev: false + /@types/babel__core@7.20.4: resolution: {integrity: sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==} dependencies: @@ -1327,6 +1387,48 @@ packages: '@babel/types': 7.23.3 dev: true + /@types/d3-array@3.2.1: + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + dev: false + + /@types/d3-color@3.1.3: + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + dev: false + + /@types/d3-ease@3.0.2: + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + dev: false + + /@types/d3-interpolate@3.0.4: + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + dependencies: + '@types/d3-color': 3.1.3 + dev: false + + /@types/d3-path@3.0.2: + resolution: {integrity: sha512-WAIEVlOCdd/NKRYTsqCpOMHQHemKBEINf8YXMYOtXH0GA7SY0dqMB78P3Uhgfy+4X+/Mlw2wDtlETkN6kQUCMA==} + dev: false + + /@types/d3-scale@4.0.8: + resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} + dependencies: + '@types/d3-time': 3.0.3 + dev: false + + /@types/d3-shape@3.1.5: + resolution: {integrity: sha512-dfEWpZJ1Pdg8meLlICX1M3WBIpxnaH2eQV2eY43Y5ysRJOTAV9f3/R++lgJKFstfrEOE2zdJ0sv5qwr2Bkic6Q==} + dependencies: + '@types/d3-path': 3.0.2 + dev: false + + /@types/d3-time@3.0.3: + resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==} + dev: false + + /@types/d3-timer@3.0.2: + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + dev: false + /@types/hoist-non-react-statics@3.3.5: resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} dependencies: @@ -1439,7 +1541,6 @@ packages: /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: true /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} @@ -1447,16 +1548,21 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: true /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true + /aria-hidden@1.2.3: + resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==} + engines: {node: '>=10'} + dependencies: + tslib: 2.6.2 + dev: false + /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: @@ -1570,12 +1676,10 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: true /bootstrap@5.3.2(@popperjs/core@2.11.8): resolution: {integrity: sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==} @@ -1590,14 +1694,12 @@ packages: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} dependencies: fill-range: 7.0.1 - dev: true /browserslist@4.22.1: resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} @@ -1625,7 +1727,6 @@ packages: /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - dev: true /caniuse-lite@1.0.30001563: resolution: {integrity: sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw==} @@ -1660,12 +1761,15 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true /classnames@2.3.2: resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} dev: false + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + dev: false + /clsx@2.0.0: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} @@ -1704,11 +1808,9 @@ packages: /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - dev: true /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -1755,11 +1857,81 @@ packages: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true - dev: true /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + /d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + dependencies: + internmap: 2.0.3 + dev: false + + /d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + dev: false + + /d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + dev: false + + /d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + dev: false + + /d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + dev: false + + /d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + dev: false + + /d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + dev: false + + /d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + dependencies: + d3-time: 3.1.0 + dev: false + + /d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + dev: false + /daisyui@3.9.4: resolution: {integrity: sha512-fvi2RGH4YV617/6DntOVGcOugOPym9jTGWW2XySb5ZpvdWO4L7bEG77VHirrnbRUEWvIEVXkBpxUz2KFj0rVnA==} engines: {node: '>=16.9.0'} @@ -1773,6 +1945,13 @@ packages: - ts-node dev: true + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.23.2 + dev: false + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -1785,6 +1964,10 @@ packages: ms: 2.1.2 dev: true + /decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + dev: false + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -1819,11 +2002,9 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: true /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: true /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} @@ -1839,6 +2020,12 @@ packages: esutils: 2.0.3 dev: true + /dom-helpers@3.4.0: + resolution: {integrity: sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==} + dependencies: + '@babel/runtime': 7.23.2 + dev: false + /dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: @@ -2127,10 +2314,19 @@ packages: engines: {node: '>=0.10.0'} dev: true + /eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: false + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true + /fast-equals@5.0.1: + resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==} + engines: {node: '>=6.0.0'} + dev: false + /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -2140,7 +2336,6 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -2158,7 +2353,6 @@ packages: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 - dev: true /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} @@ -2172,7 +2366,6 @@ packages: engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - dev: true /find-root@1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} @@ -2248,14 +2441,12 @@ packages: /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /function-bind@1.1.2: @@ -2306,14 +2497,12 @@ packages: engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - dev: true /glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} dependencies: is-glob: 4.0.3 - dev: true /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} @@ -2324,7 +2513,6 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -2436,11 +2624,9 @@ packages: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true /internal-slot@1.0.6: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} @@ -2451,6 +2637,11 @@ packages: side-channel: 1.0.4 dev: true + /internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + dev: false + /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: @@ -2487,7 +2678,6 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - dev: true /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} @@ -2517,7 +2707,6 @@ packages: /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: true /is-finalizationregistry@1.0.2: resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} @@ -2537,7 +2726,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - dev: true /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} @@ -2558,7 +2746,6 @@ packages: /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - dev: true /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} @@ -2642,7 +2829,6 @@ packages: /jiti@1.21.0: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} hasBin: true - dev: true /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2714,7 +2900,6 @@ packages: /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} - dev: true /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -2738,6 +2923,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2757,7 +2946,6 @@ packages: /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - dev: true /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} @@ -2765,7 +2953,6 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} @@ -2783,7 +2970,6 @@ packages: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 - dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -2795,13 +2981,11 @@ packages: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: true /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: true /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -2814,7 +2998,6 @@ packages: /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - dev: true /normalize-range@0.1.2: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} @@ -2828,7 +3011,6 @@ packages: /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - dev: true /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -2887,7 +3069,6 @@ packages: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 - dev: true /optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} @@ -2939,7 +3120,6 @@ packages: /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - dev: true /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} @@ -2956,22 +3136,18 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - dev: true /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - dev: true /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - dev: true /postcss-import@15.1.0(postcss@8.4.31): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} @@ -2983,7 +3159,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - dev: true /postcss-js@4.0.1(postcss@8.4.31): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} @@ -2993,7 +3168,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.31 - dev: true /postcss-load-config@4.0.1(postcss@8.4.31): resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} @@ -3010,7 +3184,6 @@ packages: lilconfig: 2.1.0 postcss: 8.4.31 yaml: 2.3.4 - dev: true /postcss-nested@6.0.1(postcss@8.4.31): resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} @@ -3020,7 +3193,6 @@ packages: dependencies: postcss: 8.4.31 postcss-selector-parser: 6.0.13 - dev: true /postcss-selector-parser@6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} @@ -3036,11 +3208,9 @@ packages: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - dev: true /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: true /postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} @@ -3049,7 +3219,6 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true /preact@10.12.1: resolution: {integrity: sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==} @@ -3088,7 +3257,6 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true /raf-schd@4.0.3: resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} @@ -3140,6 +3308,16 @@ packages: warning: 4.0.3 dev: false + /react-day-picker@8.9.1(date-fns@2.30.0)(react@18.2.0): + resolution: {integrity: sha512-W0SPApKIsYq+XCtfGeMYDoU0KbsG3wfkYtlw8l+vZp6KoBXGOlhzBUp4tNx1XiwiOZwhfdGOlj7NGSCKGSlg5Q==} + peerDependencies: + date-fns: ^2.28.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + date-fns: 2.30.0 + react: 18.2.0 + dev: false + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -3200,6 +3378,17 @@ packages: engines: {node: '>=0.10.0'} dev: true + /react-resize-detector@8.1.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w==} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + lodash: 4.17.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-router-dom@6.19.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-N6dWlcgL2w0U5HZUUqU2wlmOrSb3ighJmtQ438SWbhB1yuLTXQ8yyTBMK3BSvVjp7gBtKurT554nCtMOgxCZmQ==} engines: {node: '>=14.0.0'} @@ -3223,6 +3412,34 @@ packages: react: 18.2.0 dev: false + /react-smooth@2.0.5(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-BMP2Ad42tD60h0JW6BFaib+RJuV5dsXJK9Baxiv/HlNFjvRLqA9xrNKxVWnUIZPQfzUwGXIlU/dSYLU+54YGQA==} + peerDependencies: + prop-types: ^15.6.0 + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + fast-equals: 5.0.1 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-transition-group: 2.9.0(react-dom@18.2.0)(react@18.2.0) + dev: false + + /react-transition-group@2.9.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==} + peerDependencies: + react: '>=15.0.0' + react-dom: '>=15.0.0' + dependencies: + dom-helpers: 3.4.0 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-lifecycles-compat: 3.0.4 + dev: false + /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: @@ -3258,14 +3475,40 @@ packages: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 - dev: true /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - dev: true + + /recharts-scale@0.4.5: + resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} + dependencies: + decimal.js-light: 2.5.1 + dev: false + + /recharts@2.9.3(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-B61sKrDlTxHvYwOCw8eYrD6rTA2a2hJg0avaY8qFI1ZYdHKvU18+J5u7sBMFg//wfJ/C5RL5+HsXt5e8tcJNLg==} + engines: {node: '>=12'} + peerDependencies: + prop-types: ^15.6.0 + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + classnames: 2.3.2 + eventemitter3: 4.0.7 + lodash: 4.17.21 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-is: 16.13.1 + react-resize-detector: 8.1.0(react-dom@18.2.0)(react@18.2.0) + react-smooth: 2.0.5(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.1 + victory-vendor: 36.6.12 + dev: false /redux@4.2.1: resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} @@ -3322,7 +3565,6 @@ packages: /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} @@ -3343,7 +3585,6 @@ packages: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 - dev: true /safe-array-concat@1.0.1: resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} @@ -3416,7 +3657,6 @@ packages: /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - dev: true /source-map@0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} @@ -3490,7 +3730,6 @@ packages: mz: 2.7.0 pirates: 4.0.6 ts-interface-checker: 0.1.13 - dev: true /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -3509,6 +3748,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + /tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + dev: false + + /tailwind-merge@1.14.0: + resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==} + dev: false + /tailwindcss@3.3.5: resolution: {integrity: sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==} engines: {node: '>=14.0.0'} @@ -3538,7 +3785,6 @@ packages: sucrase: 3.34.0 transitivePeerDependencies: - ts-node - dev: true /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -3549,13 +3795,11 @@ packages: engines: {node: '>=0.8'} dependencies: thenify: 3.3.1 - dev: true /thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} dependencies: any-promise: 1.3.0 - dev: true /tiny-invariant@1.3.1: resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} @@ -3570,11 +3814,9 @@ packages: engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 - dev: true /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - dev: true /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -3990,7 +4232,25 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true + + /victory-vendor@36.6.12: + resolution: {integrity: sha512-pJrTkNHln+D83vDCCSUf0ZfxBvIaVrFHmrBOsnnLAbdqfudRACAj51He2zU94/IWq9464oTADcPVkmWAfNMwgA==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.8 + '@types/d3-shape': 3.1.5 + '@types/d3-time': 3.0.3 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + dev: false /vite@4.5.0: resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} @@ -4091,7 +4351,6 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -4105,7 +4364,6 @@ packages: /yaml@2.3.4: resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} engines: {node: '>= 14'} - dev: true /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index c85efdb..1e759ce 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,21 +1,103 @@ /** @type {import('tailwindcss').Config} */ -const defaultTheme = require('tailwindcss/defaultTheme') +const defaultTheme = require("tailwindcss/defaultTheme"); export default { - content: ["./src/**/*.{js,jsx}"], + content: [ + "./src/**/*.{js,jsx}", + "./node_modules/@tremor/**/*.{js,ts,jsx,tsx}", + ], + theme: { extend: { fontFamily: { - 'sans': ['"Proxima Nova"', ...defaultTheme.fontFamily.sans], + sans: ['"Proxima Nova"', ...defaultTheme.fontFamily.sans], + }, + colors:{ + "dark-tremor": { + brand: { + faint: "#0B1229", // custom + muted: "#172554", // blue-950 + subtle: "#1e40af", // blue-800 + DEFAULT: "#3b82f6", // blue-500 + emphasis: "#60a5fa", // blue-400 + inverted: "#030712", // gray-950 + }, + background: { + muted: "#131A2B", // custom + subtle: "#1f2937", // gray-800 + DEFAULT: "#111827", // gray-900 + emphasis: "#d1d5db", // gray-300 + }, + border: { + DEFAULT: "#1f2937", // gray-800 + }, + ring: { + DEFAULT: "#1f2937", // gray-800 + }, + content: { + subtle: "#4b5563", // gray-600 + DEFAULT: "#6b7280", // gray-500 + emphasis: "#e5e7eb", // gray-200 + strong: "#f9fafb", // gray-50 + inverted: "#000000", // black + }, + }, + }, + boxShadow:{ + "dark-tremor-input": "0 1px 2px 0 rgb(0 0 0 / 0.05)", + "dark-tremor-card": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)", + "dark-tremor-dropdown": "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)", + }, + borderRadius: { + "tremor-small": "0.375rem", + "tremor-default": "0.5rem", + "tremor-full": "9999px", + }, + fontSize: { + "tremor-label": ["0.75rem"], + "tremor-default": ["0.875rem", { lineHeight: "1.25rem" }], + "tremor-title": ["1.125rem", { lineHeight: "1.75rem" }], + "tremor-metric": ["1.875rem", { lineHeight: "2.25rem" }], }, }, }, - plugins: [require("daisyui"), - require("@tailwindcss/typography"), - require("daisyui") - ], + safelist: [ + { + pattern: + /^(bg-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + variants: ["hover", "ui-selected"], + }, + { + pattern: + /^(text-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + variants: ["hover", "ui-selected"], + }, + { + pattern: + /^(border-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + variants: ["hover", "ui-selected"], + }, + { + pattern: + /^(ring-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + }, + { + pattern: + /^(stroke-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + }, + { + pattern: + /^(fill-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950))$/, + }, + ], + plugins: [ + require("daisyui"), + require("@tailwindcss/typography"), + require("daisyui"), + require("@headlessui/tailwindcss"), + ], daisyui: { themes: ["light", "night"], }, -} +}; From e39b7c52d8f383332d37d7756a8ede218b533e46 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 17:52:37 +0700 Subject: [PATCH 029/120] Installing necessary modules for dashboard. --- frontend/package.json | 1 + frontend/pnpm-lock.yaml | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/frontend/package.json b/frontend/package.json index c2ac047..fed56d1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,6 +21,7 @@ "@fullcalendar/interaction": "^6.1.9", "@fullcalendar/react": "^6.1.9", "@fullcalendar/timegrid": "^6.1.9", + "@heroicons/react": "1.0.6", "@mui/icons-material": "^5.14.16", "@mui/material": "^5.14.17", "@mui/system": "^5.14.17", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 71f96fe..afbf464 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -38,6 +38,9 @@ dependencies: '@fullcalendar/timegrid': specifier: ^6.1.9 version: 6.1.9(@fullcalendar/core@6.1.9) + '@heroicons/react': + specifier: 1.0.6 + version: 1.0.6(react@18.2.0) '@mui/icons-material': specifier: ^5.14.16 version: 5.14.18(@mui/material@5.14.18)(@types/react@18.2.37)(react@18.2.0) @@ -916,6 +919,14 @@ packages: tailwindcss: 3.3.5 dev: false + /@heroicons/react@1.0.6(react@18.2.0): + resolution: {integrity: sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==} + peerDependencies: + react: '>= 16' + dependencies: + react: 18.2.0 + dev: false + /@humanwhocodes/config-array@0.11.13: resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} From 9d2ce023503e25465167f8e195c6f27d1bcd9575 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 18:14:58 +0700 Subject: [PATCH 030/120] Constructing dashboard component. --- frontend/src/App.jsx | 3 +- frontend/src/components/dashboard.jsx | 59 +++++++++++++++++++++++++++ frontend/tailwind.config.js | 38 ++++++++--------- 3 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 frontend/src/components/dashboard.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index ad9dc97..eb6bb03 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -12,6 +12,7 @@ import IconSideNav from "./components/navigations/IconSideNav"; import Eisenhower from "./components/eisenhowerMatrix/Eisenhower"; import PrivateRoute from "./PrivateRoute"; import ProfileUpdatePage from "./components/profilePage"; +import Dashboard from "./components/dashboard"; const App = () => { @@ -26,7 +27,7 @@ const App = () => {
- } /> + } /> }> } /> diff --git a/frontend/src/components/dashboard.jsx b/frontend/src/components/dashboard.jsx new file mode 100644 index 0000000..dea56a9 --- /dev/null +++ b/frontend/src/components/dashboard.jsx @@ -0,0 +1,59 @@ +"use client"; + + import { + Card, + Grid, + Tab, + TabGroup, + TabList, + TabPanel, + TabPanels, + Text, + Title, + } from "@tremor/react"; + +export default function DashboardExample() { + return ( +
+ Dashboard + Lorem ipsum dolor sit amet, consetetur sadipscing elitr. + + + + Overview + Detail + + + + + + {/* Placeholder to set height */} +
+ + + {/* Placeholder to set height */} +
+ + + {/* Placeholder to set height */} +
+ + +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ ); +} \ No newline at end of file diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 1e759ce..b388349 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -14,40 +14,40 @@ export default { sans: ['"Proxima Nova"', ...defaultTheme.fontFamily.sans], }, colors:{ - "dark-tremor": { + tremor: { brand: { - faint: "#0B1229", // custom - muted: "#172554", // blue-950 - subtle: "#1e40af", // blue-800 + faint: "#eff6ff", // blue-50 + muted: "#bfdbfe", // blue-200 + subtle: "#60a5fa", // blue-400 DEFAULT: "#3b82f6", // blue-500 - emphasis: "#60a5fa", // blue-400 - inverted: "#030712", // gray-950 + emphasis: "#1d4ed8", // blue-700 + inverted: "#ffffff", // white }, background: { - muted: "#131A2B", // custom - subtle: "#1f2937", // gray-800 - DEFAULT: "#111827", // gray-900 - emphasis: "#d1d5db", // gray-300 + muted: "#f9fafb", // gray-50 + subtle: "#f3f4f6", // gray-100 + DEFAULT: "#ffffff", // white + emphasis: "#374151", // gray-700 }, border: { - DEFAULT: "#1f2937", // gray-800 + DEFAULT: "#e5e7eb", // gray-200 }, ring: { - DEFAULT: "#1f2937", // gray-800 + DEFAULT: "#e5e7eb", // gray-200 }, content: { - subtle: "#4b5563", // gray-600 + subtle: "#9ca3af", // gray-400 DEFAULT: "#6b7280", // gray-500 - emphasis: "#e5e7eb", // gray-200 - strong: "#f9fafb", // gray-50 - inverted: "#000000", // black + emphasis: "#374151", // gray-700 + strong: "#111827", // gray-900 + inverted: "#ffffff", // white }, }, }, boxShadow:{ - "dark-tremor-input": "0 1px 2px 0 rgb(0 0 0 / 0.05)", - "dark-tremor-card": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)", - "dark-tremor-dropdown": "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)", + "tremor-input": "0 1px 2px 0 rgb(0 0 0 / 0.05)", + "tremor-card": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)", + "tremor-dropdown": "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)", }, borderRadius: { "tremor-small": "0.375rem", From f1183db1bafef2acfa67a13215e9d046a3889c7f Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 19:01:59 +0700 Subject: [PATCH 031/120] Constructing dashboard. --- frontend/src/App.jsx | 2 +- frontend/src/components/dashboard/KpiCard.jsx | 21 +++++++++++ .../components/{ => dashboard}/dashboard.jsx | 36 +++++++++---------- 3 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 frontend/src/components/dashboard/KpiCard.jsx rename frontend/src/components/{ => dashboard}/dashboard.jsx (68%) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index eb6bb03..28d2d19 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -12,7 +12,7 @@ import IconSideNav from "./components/navigations/IconSideNav"; import Eisenhower from "./components/eisenhowerMatrix/Eisenhower"; import PrivateRoute from "./PrivateRoute"; import ProfileUpdatePage from "./components/profilePage"; -import Dashboard from "./components/dashboard"; +import Dashboard from "./components/dashboard/dashboard"; const App = () => { diff --git a/frontend/src/components/dashboard/KpiCard.jsx b/frontend/src/components/dashboard/KpiCard.jsx new file mode 100644 index 0000000..08d7a99 --- /dev/null +++ b/frontend/src/components/dashboard/KpiCard.jsx @@ -0,0 +1,21 @@ + +import { BadgeDelta, Card, Flex, Metric, ProgressBar, Text } from "@tremor/react"; + +export default function KpiCard() { + return ( + + +
+ Sales + $ 12,699 +
+ 13.2% +
+ + 68% ($ 149,940) + $ 220,500 + + +
+ ); +} \ No newline at end of file diff --git a/frontend/src/components/dashboard.jsx b/frontend/src/components/dashboard/dashboard.jsx similarity index 68% rename from frontend/src/components/dashboard.jsx rename to frontend/src/components/dashboard/dashboard.jsx index dea56a9..9cefbe2 100644 --- a/frontend/src/components/dashboard.jsx +++ b/frontend/src/components/dashboard/dashboard.jsx @@ -1,22 +1,21 @@ -"use client"; +import { + Card, + Grid, + Tab, + TabGroup, + TabList, + TabPanel, + TabPanels, + Text, + Title, +} from "@tremor/react"; +import KpiCard from "./kpiCard"; - import { - Card, - Grid, - Tab, - TabGroup, - TabList, - TabPanel, - TabPanels, - Text, - Title, - } from "@tremor/react"; - -export default function DashboardExample() { +export default function Dashboard() { return (
Dashboard - Lorem ipsum dolor sit amet, consetetur sadipscing elitr. + All of your progress will be shown right here. @@ -26,10 +25,7 @@ export default function DashboardExample() { - - {/* Placeholder to set height */} -
- + {/* Placeholder to set height */}
@@ -56,4 +52,4 @@ export default function DashboardExample() {
); -} \ No newline at end of file +} From 5d86550382651a7154c4569acf6abe785cc668b5 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 19:47:37 +0700 Subject: [PATCH 032/120] Modifying signup page. --- .../components/authentication/SignUpPage.jsx | 210 ++++++++++++------ 1 file changed, 137 insertions(+), 73 deletions(-) diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 28eb1c2..06f3ce0 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -1,7 +1,6 @@ import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import axiosapi from "../../api/AuthenticationApi"; - import Avatar from "@mui/material/Avatar"; import Button from "@mui/material/Button"; import CssBaseline from "@mui/material/CssBaseline"; @@ -13,8 +12,9 @@ import Grid from "@mui/material/Grid"; import Box from "@mui/material/Box"; import LockOutlinedIcon from "@mui/icons-material/LockOutlined"; import Typography from "@mui/material/Typography"; -import Container from "@mui/material/Container"; -import { createTheme, ThemeProvider } from "@mui/material/styles"; +import { useCallback } from "react"; +import Particles from "react-tsparticles"; +import { loadFull } from "tsparticles"; function Copyright(props) { return ( @@ -29,7 +29,6 @@ function Copyright(props) { ); } -const defaultTheme = createTheme(); export default function SignUp() { const Navigate = useNavigate(); @@ -62,82 +61,147 @@ export default function SignUp() { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); }; + { + /* Particles Loader*/ + } + const particlesInit = useCallback(async (engine) => { + console.log(engine); + await loadFull(engine); + }, []); + + const particlesLoaded = useCallback(async (container) => { + console.log(container); + }, []); + return ( - - - - - - - +
+ {/* Particles Container */} +
+ +
+
+
+ {/* Register Form */} Sign up - - - - - - - - - - - - - } - label="I want to receive inspiration, marketing promotions and updates via email." - /> - - +
+ + + + } + label="I want to receive inspiration, marketing promotions and updates via email." + /> - - - - Already have an account? Sign in - - - - - - - - + {/* Already have an account? */} + + +
+
+
); + } From 61a11d51d5a52a050bac5ef12d383a6faa016319 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 20:06:04 +0700 Subject: [PATCH 033/120] Modifying signup page. --- .../components/authentication/SignUpPage.jsx | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 06f3ce0..8a2168c 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -1,16 +1,11 @@ import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import axiosapi from "../../api/AuthenticationApi"; -import Avatar from "@mui/material/Avatar"; import Button from "@mui/material/Button"; -import CssBaseline from "@mui/material/CssBaseline"; import TextField from "@mui/material/TextField"; import FormControlLabel from "@mui/material/FormControlLabel"; import Checkbox from "@mui/material/Checkbox"; import Link from "@mui/material/Link"; -import Grid from "@mui/material/Grid"; -import Box from "@mui/material/Box"; -import LockOutlinedIcon from "@mui/icons-material/LockOutlined"; import Typography from "@mui/material/Typography"; import { useCallback } from "react"; import Particles from "react-tsparticles"; @@ -18,18 +13,20 @@ import { loadFull } from "tsparticles"; function Copyright(props) { return ( - +
{"Copyright © "} - + TurTask - {" "} + {" "} {new Date().getFullYear()} {"."} - +
); } - export default function SignUp() { const Navigate = useNavigate(); @@ -41,7 +38,7 @@ export default function SignUp() { const [error, setError] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); - const handleSubmit = async e => { + const handleSubmit = async (e) => { e.preventDefault(); setIsSubmitting(true); setError(null); @@ -57,7 +54,7 @@ export default function SignUp() { Navigate("/login"); }; - const handleChange = e => { + const handleChange = (e) => { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); }; @@ -73,9 +70,11 @@ export default function SignUp() { console.log(container); }, []); - return ( -
+
{/* Particles Container */}
-
+
{/* Register Form */} - - Sign up - +

Signup

} label="I want to receive inspiration, marketing promotions and updates via email." /> - - {/* Already have an account? */} - + {/* Already have an account? */} + +
); - } From de62190f0c2b199f35672c4bc764e568c687da8c Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Sun, 19 Nov 2023 20:32:21 +0700 Subject: [PATCH 034/120] Completed Signup page improvement. --- .../components/authentication/SignUpPage.jsx | 110 ++++++++++-------- 1 file changed, 62 insertions(+), 48 deletions(-) diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 8a2168c..daf452f 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -1,12 +1,6 @@ import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import axiosapi from "../../api/AuthenticationApi"; -import Button from "@mui/material/Button"; -import TextField from "@mui/material/TextField"; -import FormControlLabel from "@mui/material/FormControlLabel"; -import Checkbox from "@mui/material/Checkbox"; -import Link from "@mui/material/Link"; -import Typography from "@mui/material/Typography"; import { useCallback } from "react"; import Particles from "react-tsparticles"; import { loadFull } from "tsparticles"; @@ -108,13 +102,13 @@ export default function SignUp() { }, particles: { color: { - value: "#008000", + value: "#023020", }, links: { - color: "#00ff00", + color: "#228B22", distance: 150, enable: true, - opacity: 0.1, + opacity: 0.5, width: 1, }, move: { @@ -141,7 +135,7 @@ export default function SignUp() { type: "circle", }, size: { - value: { min: 4, max: 5 }, + value: { min: 6, max: 8 }, }, }, detectRetina: true, @@ -152,55 +146,75 @@ export default function SignUp() {
{/* Register Form */}

Signup

-
- + + - + {/* Username Input */} +
+ + - + {/* Password Input */} +
+ + - } - label="I want to receive inspiration, marketing promotions and updates via email." +
+

+
+ - - {/* Already have an account? */} - - + +
+ + {/* Login Button */} + + {/* Already have an account? */} +
From e372c1b3ba4c5bf17e046e8a47c324cd4c6b95b4 Mon Sep 17 00:00:00 2001 From: sosokker Date: Mon, 20 Nov 2023 01:38:34 +0700 Subject: [PATCH 035/120] Update API url --- backend/core/urls.py | 2 +- backend/dashboard/models.py | 3 --- ...recurrencetask_completed_todo_completed.py | 23 +++++++++++++++++++ backend/tasks/models.py | 3 ++- 4 files changed, 26 insertions(+), 5 deletions(-) delete mode 100644 backend/dashboard/models.py create mode 100644 backend/tasks/migrations/0014_recurrencetask_completed_todo_completed.py diff --git a/backend/core/urls.py b/backend/core/urls.py index 434a21f..06a4fd2 100644 --- a/backend/core/urls.py +++ b/backend/core/urls.py @@ -27,5 +27,5 @@ urlpatterns = [ path('api/schema/', SpectacularAPIView.as_view(), name='schema'), path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), - path('dashboard/', include('dashboard.urls')), + path('api/', include('dashboard.urls')), ] \ No newline at end of file diff --git a/backend/dashboard/models.py b/backend/dashboard/models.py deleted file mode 100644 index 71a8362..0000000 --- a/backend/dashboard/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/backend/tasks/migrations/0014_recurrencetask_completed_todo_completed.py b/backend/tasks/migrations/0014_recurrencetask_completed_todo_completed.py new file mode 100644 index 0000000..d89360d --- /dev/null +++ b/backend/tasks/migrations/0014_recurrencetask_completed_todo_completed.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.6 on 2023-11-17 16:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tasks', '0013_alter_recurrencetask_recurrence_rule'), + ] + + operations = [ + migrations.AddField( + model_name='recurrencetask', + name='completed', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='todo', + name='completed', + field=models.BooleanField(default=False), + ), + ] diff --git a/backend/tasks/models.py b/backend/tasks/models.py index a8fc4e5..9a914c0 100644 --- a/backend/tasks/models.py +++ b/backend/tasks/models.py @@ -18,7 +18,6 @@ class Task(models.Model): :param title: Title of the task. :param notes: Optional additional notes for the task. :param tags: Associated tags for the task. - :param completed: A boolean field indicating whether the task is completed. :param importance: The importance of the task (range: 1 to 5) :param difficulty: The difficulty of the task (range: 1 to 5). :param challenge: Associated challenge (optional). @@ -62,12 +61,14 @@ class Todo(Task): NOT_IMPORTANT_URGENT = 3, 'Not Important & Urgent' NOT_IMPORTANT_NOT_URGENT = 4, 'Not Important & Not Urgent' + completed = models.BooleanField(default=False) priority = models.PositiveSmallIntegerField(choices=EisenhowerMatrix.choices, default=EisenhowerMatrix.NOT_IMPORTANT_NOT_URGENT) def __str__(self): return self.title class RecurrenceTask(Task): + completed = models.BooleanField(default=False) recurrence_rule = models.CharField() def __str__(self) -> str: From c71020f94737c735f9b5977aede16ae8dff22ca3 Mon Sep 17 00:00:00 2001 From: Sirin Puenggun Date: Mon, 20 Nov 2023 01:52:06 +0700 Subject: [PATCH 036/120] Fix Layout and remove buttom checkbox --- .../src/components/authentication/SignUpPage.jsx | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index daf452f..0370d55 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -192,26 +192,14 @@ export default function SignUp() { />


-
- - -
{/* Login Button */} {/* Already have an account? */} -
- + From ae2b55bf0e2e6f03b9651d9ca744642e3cfa86c2 Mon Sep 17 00:00:00 2001 From: sosokker Date: Mon, 20 Nov 2023 02:01:58 +0700 Subject: [PATCH 037/120] Add google login to signup / Increase profile dropdown z --- .../components/authentication/LoginPage.jsx | 4 ++- .../components/authentication/SignUpPage.jsx | 33 +++++++++++++++++++ .../src/components/navigations/Navbar.jsx | 2 +- frontend/src/components/navigators/Navbar.jsx | 0 4 files changed, 37 insertions(+), 2 deletions(-) delete mode 100644 frontend/src/components/navigators/Navbar.jsx diff --git a/frontend/src/components/authentication/LoginPage.jsx b/frontend/src/components/authentication/LoginPage.jsx index 12ad18e..a48c075 100644 --- a/frontend/src/components/authentication/LoginPage.jsx +++ b/frontend/src/components/authentication/LoginPage.jsx @@ -7,6 +7,8 @@ import { loadFull } from "tsparticles"; import refreshAccessToken from "./refreshAcesstoken"; import axiosapi from "../../api/AuthenticationApi"; import { useAuth } from "../../hooks/authentication/IsAuthenticated"; +import { FcGoogle } from "react-icons/fc"; + function LoginPage() { const Navigate = useNavigate(); @@ -208,7 +210,7 @@ function LoginPage() { className="btn btn-outline btn-secondary w-full " onClick={() => googleLoginImplicit()} > - Login with Google + Login with Google {/* Forgot Password Link */}
diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 0370d55..50d893b 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -4,6 +4,9 @@ import axiosapi from "../../api/AuthenticationApi"; import { useCallback } from "react"; import Particles from "react-tsparticles"; import { loadFull } from "tsparticles"; +import { FcGoogle } from "react-icons/fc"; +import { useGoogleLogin } from "@react-oauth/google"; + function Copyright(props) { return ( @@ -64,6 +67,28 @@ export default function SignUp() { console.log(container); }, []); + const googleLoginImplicit = useGoogleLogin({ + flow: "auth-code", + redirect_uri: "postmessage", + onSuccess: async (response) => { + try { + const loginResponse = await axiosapi.googleLogin(response.code); + if (loginResponse && loginResponse.data) { + const { access_token, refresh_token } = loginResponse.data; + + localStorage.setItem("access_token", access_token); + localStorage.setItem("refresh_token", refresh_token); + setIsAuthenticated(true); + Navigate("/"); + } + } catch (error) { + console.error("Error with the POST request:", error); + setIsAuthenticated(false); + } + }, + onError: (errorResponse) => console.log(errorResponse), + }); + return (
Signup +
OR
+ {/* Login with Google Button */} + {/* Already have an account? */}
diff --git a/frontend/src/components/navigations/Navbar.jsx b/frontend/src/components/navigations/Navbar.jsx index 0c95389..aeb0065 100644 --- a/frontend/src/components/navigations/Navbar.jsx +++ b/frontend/src/components/navigations/Navbar.jsx @@ -39,7 +39,7 @@ function NavBar() {