From a569150ae8e9944bf025ed022065f114aa236170 Mon Sep 17 00:00:00 2001 From: Hannes Date: Thu, 18 Jul 2024 13:39:46 +0200 Subject: [PATCH 01/22] vingo: seasons --- vingo/database/models.go | 6 ++++++ vingo/database/seasons.go | 11 +++++++++++ vingo/handlers/seasons.go | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 vingo/database/seasons.go create mode 100644 vingo/handlers/seasons.go diff --git a/vingo/database/models.go b/vingo/database/models.go index ce66161..ff72350 100644 --- a/vingo/database/models.go +++ b/vingo/database/models.go @@ -68,3 +68,9 @@ type Scan struct { CardSerial string `json:"cardSerial" gorm:"index"` Card Card `json:"-" gorm:"foreignKey:CardSerial;references:Serial"` } + +type Season struct { + BaseModel + StartDate time.Time `json:"startDate"` + EndDate time.Time `json:"endDate"` +} diff --git a/vingo/database/seasons.go b/vingo/database/seasons.go new file mode 100644 index 0000000..4cd36ab --- /dev/null +++ b/vingo/database/seasons.go @@ -0,0 +1,11 @@ +package database + +func (Season) GetAll() ([]Season, error) { + var seasons []Season + result := gorm_db.Find(&seasons) + return seasons, result.Error +} + +func (s Season) Create() error { + return gorm_db.Create(s).Error +} diff --git a/vingo/handlers/seasons.go b/vingo/handlers/seasons.go new file mode 100644 index 0000000..bcfed09 --- /dev/null +++ b/vingo/handlers/seasons.go @@ -0,0 +1,36 @@ +package handlers + +import ( + "vingo/database" + + "github.com/gofiber/fiber/v2" +) + +type Seasons struct{} + +func (Seasons) Get(c *fiber.Ctx) error { + seasons, err := database.Season{}.GetAll() + if err != nil { + logger.Println(err) + return c.Status(500).SendString("Error getting seasons") + } + + return c.JSON(seasons) +} + +func (Seasons) Create(c *fiber.Ctx) error { + season := database.Season{} + err := c.BodyParser(&season) + if err != nil { + logger.Println(err) + return c.Status(400).SendString("Invalid payload") + } + + err = season.Create() + if err != nil { + logger.Println(err) + return c.Status(500).SendString("Error creating season") + } + + return c.SendStatus(200) +} From 83643b26f3f5803e2e674dc9cba095fa6dd9f7cf Mon Sep 17 00:00:00 2001 From: Hannes Date: Thu, 18 Jul 2024 13:53:23 +0200 Subject: [PATCH 02/22] vingo: add streakdays --- vingo/database/days.go | 11 +++-------- vingo/database/db.go | 2 +- vingo/database/models.go | 5 +++++ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/vingo/database/days.go b/vingo/database/days.go index 3187cb9..c2b5e02 100644 --- a/vingo/database/days.go +++ b/vingo/database/days.go @@ -2,11 +2,6 @@ package database import "time" -type Day struct { - Id int - Date time.Time -} - func CreateDays(first_day time.Time, last_day time.Time) error { tx, err := db.Begin() if err != nil { @@ -34,15 +29,15 @@ func CreateDays(first_day time.Time, last_day time.Time) error { return nil } -func GetDays() ([]Day, error) { +func GetDays() ([]StreakDay, error) { rows, err := db.Query("SELECT id, date FROM days ORDER BY date;") if err != nil { return nil, err } - days := make([]Day, 0) + days := make([]StreakDay, 0) for rows.Next() { - var day Day + var day StreakDay rows.Scan(&day.Id, &day.Date) days = append(days, day) } diff --git a/vingo/database/db.go b/vingo/database/db.go index 157c7ae..f8dd8c5 100644 --- a/vingo/database/db.go +++ b/vingo/database/db.go @@ -30,7 +30,7 @@ func OpenDatabase(db_string string) { log.Fatal(err) } - err = new_db.AutoMigrate(&User{}, &Card{}, &Scan{}, &Day{}, &Settings{}, &Season{}) + err = new_db.AutoMigrate(&User{}, &Card{}, &Scan{}, &StreakDay{}, &Settings{}, &Season{}) if err != nil { log.Println("Error migrating database") log.Fatal(err) diff --git a/vingo/database/models.go b/vingo/database/models.go index ff72350..f5d8085 100644 --- a/vingo/database/models.go +++ b/vingo/database/models.go @@ -74,3 +74,8 @@ type Season struct { StartDate time.Time `json:"startDate"` EndDate time.Time `json:"endDate"` } + +type StreakDay struct { + BaseModel + Date time.Time +} From 93dcced82ac7e36929599ed1f652b87284952746 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Thu, 18 Jul 2024 17:19:44 +0200 Subject: [PATCH 03/22] vinvoor: add a settings page --- vingo/handlers/settings.go | 2 +- vinvoor/src/cards/CardsTableBody.tsx | 7 +- .../src/leaderboard/LeaderboardTableBody.tsx | 1 - vinvoor/src/main.tsx | 5 +- vinvoor/src/navbar/NavBar.tsx | 9 +- vinvoor/src/settings/Settings.tsx | 0 vinvoor/src/settings/SettingsOverview.tsx | 170 ++++++++++++++++++ vinvoor/src/types/settings.ts | 46 +++++ vinvoor/src/util/fetch.ts | 4 +- 9 files changed, 231 insertions(+), 13 deletions(-) delete mode 100644 vinvoor/src/settings/Settings.tsx create mode 100644 vinvoor/src/settings/SettingsOverview.tsx create mode 100644 vinvoor/src/types/settings.ts diff --git a/vingo/handlers/settings.go b/vingo/handlers/settings.go index dbbeb53..4795e50 100644 --- a/vingo/handlers/settings.go +++ b/vingo/handlers/settings.go @@ -24,7 +24,7 @@ func (Settings) Update(c *fiber.Ctx) error { sess.Set(STORE_USER, &user) sess.Save() - return c.SendStatus(200) + return c.Status(200).JSON(map[string]bool{}) } func (Settings) Get(c *fiber.Ctx) error { diff --git a/vinvoor/src/cards/CardsTableBody.tsx b/vinvoor/src/cards/CardsTableBody.tsx index 1d01ef7..b4659ef 100644 --- a/vinvoor/src/cards/CardsTableBody.tsx +++ b/vinvoor/src/cards/CardsTableBody.tsx @@ -68,10 +68,9 @@ export const CardsTableBody: FC = ({ (cards) => setCards(cards) ); }) - .catch((error) => { - enqueueSnackbar(nameSaveFailure, { variant: "error" }); - console.log(error); - }); + .catch(() => + enqueueSnackbar(nameSaveFailure, { variant: "error" }) + ); }) .catch(() => {}); // Required otherwise the confirm dialog will throw an error in the console }; diff --git a/vinvoor/src/leaderboard/LeaderboardTableBody.tsx b/vinvoor/src/leaderboard/LeaderboardTableBody.tsx index 7f94e90..dcf0999 100644 --- a/vinvoor/src/leaderboard/LeaderboardTableBody.tsx +++ b/vinvoor/src/leaderboard/LeaderboardTableBody.tsx @@ -45,7 +45,6 @@ const getPositionChange = (positionChange: number) => { const getPosition = (position: number) => { switch (position) { case 1: - // return ; return ( diff --git a/vinvoor/src/main.tsx b/vinvoor/src/main.tsx index f45b059..57bb121 100644 --- a/vinvoor/src/main.tsx +++ b/vinvoor/src/main.tsx @@ -14,6 +14,7 @@ import { Cards } from "./cards/Cards.tsx"; import { ErrorPage } from "./errors/ErrorPage.tsx"; import { Leaderboard } from "./leaderboard/Leaderboard.tsx"; import { Scans } from "./scans/Scans.tsx"; +import { SettingsOverview } from "./settings/SettingsOverview.tsx"; import { ThemeProvider } from "./theme/ThemeProvider"; import { Login } from "./user/Login.tsx"; import { Logout } from "./user/Logout.tsx"; @@ -47,8 +48,8 @@ const router = createBrowserRouter([ }, { path: "settings", - - } + element: , + }, ], }, ]); diff --git a/vinvoor/src/navbar/NavBar.tsx b/vinvoor/src/navbar/NavBar.tsx index a07435d..cabed2c 100644 --- a/vinvoor/src/navbar/NavBar.tsx +++ b/vinvoor/src/navbar/NavBar.tsx @@ -1,6 +1,7 @@ -import LeaderboardIcon from "@mui/icons-material/Leaderboard"; +import { LeaderboardOutlined } from "@mui/icons-material"; import { AppBar, Box, Container, Toolbar } from "@mui/material"; import { + CogOutline, CreditCardMultipleOutline, CreditCardScanOutline, } from "mdi-material-ui"; @@ -20,10 +21,12 @@ export interface PageIcon { const navBarPages: PageIcon[] = [ { page: "Scans", icon: }, { page: "Cards", icon: }, - { page: "Leaderboard", icon: }, + { page: "Leaderboard", icon: }, ]; -const userMenuPages: PageIcon[] = []; +const userMenuPages: PageIcon[] = [ + { page: "Settings", icon: }, +]; export const NavBar = () => { const { diff --git a/vinvoor/src/settings/Settings.tsx b/vinvoor/src/settings/Settings.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/vinvoor/src/settings/SettingsOverview.tsx b/vinvoor/src/settings/SettingsOverview.tsx new file mode 100644 index 0000000..493ef66 --- /dev/null +++ b/vinvoor/src/settings/SettingsOverview.tsx @@ -0,0 +1,170 @@ +import { + Box, + Button, + Checkbox, + FormControl, + FormControlLabel, + Grid, + Paper, + Tooltip, + Typography, +} from "@mui/material"; +import { useConfirm } from "material-ui-confirm"; +import { HelpCircleOutline } from "mdi-material-ui"; +import { useSnackbar } from "notistack"; +import { ChangeEvent, useState } from "react"; +import { LoadingSkeleton } from "../components/LoadingSkeleton"; +import { useFetch } from "../hooks/useFetch"; +import { + adjustableSettings, + converSettingsJSON, + Settings, +} from "../types/settings"; +import { patchApi } from "../util/fetch"; + +const defaultSettings: Settings = { + id: -1, + createdAt: new Date(), + scanInOut: false, + leaderboard: false, + public: false, +}; + +const saveSuccess = "Settings saved successfully"; +const saveFailure = "Unable to save settings"; +const handleDeleteContent = ( + + + Are you sure you want to delete all your data? + + + This is irreversible! + + +); + +export const SettingsOverview = () => { + const [settings, setSettings] = useState(defaultSettings); + const { loading } = useFetch( + "settings", + setSettings, + converSettingsJSON + ); + const { enqueueSnackbar } = useSnackbar(); + const confirm = useConfirm(); + + const handleChange = (event: ChangeEvent) => { + setSettings({ + ...settings, + [event.target.name]: event.target.checked, + }); + }; + + const handleSubmit = () => { + patchApi("settings", { + scanInOut: settings.scanInOut, + leaderboard: settings.leaderboard, + public: settings.public, + }) + .then(() => enqueueSnackbar(saveSuccess, { variant: "success" })) + .catch((error) => enqueueSnackbar(error, { variant: "error" })); + }; + + const handleDelete = () => { + confirm({ + title: "Delete data", + content: handleDeleteContent, + acknowledgement: "Delete all my data", + confirmationText: "Delete", + confirmationButtonProps: { color: "error" }, + }) + .then(() => + enqueueSnackbar("This is not possible yet", { + variant: "error", + }) + ) + .catch(() => {}); + }; + + return ( + + + + + + {adjustableSettings.map((setting) => ( + + } + label={ + + + {setting.name} + + + + + + } + key={setting.id} + /> + ))} + + + + + + + + More settings coming soon! + + + + + + + + + + + + + ); +}; diff --git a/vinvoor/src/types/settings.ts b/vinvoor/src/types/settings.ts new file mode 100644 index 0000000..583d1c1 --- /dev/null +++ b/vinvoor/src/types/settings.ts @@ -0,0 +1,46 @@ +import { Base, BaseJSON } from "./general"; + +interface SettingsJSON extends BaseJSON { + scanInOut: boolean; + leaderboard: boolean; + public: boolean; +} + +export interface Settings extends Base { + scanInOut: boolean; + leaderboard: boolean; + public: boolean; +} + +export const converSettingsJSON = (settingsJSON: SettingsJSON): Settings => ({ + id: settingsJSON.id, + createdAt: new Date(settingsJSON.createdAt), + scanInOut: settingsJSON.scanInOut, + leaderboard: settingsJSON.leaderboard, + public: settingsJSON.public, +}); + +interface AdjustableSettings { + id: keyof Settings; + name: string; + description: string; +} + +export const adjustableSettings: AdjustableSettings[] = [ + { + id: "scanInOut", + name: "Scan in and out", + description: + "A second scan on the same day will be interpreted as a scan out", + }, + { + id: "leaderboard", + name: "Leaderboard", + description: "Show yourself on the leaderboard", + }, + { + id: "public", + name: "Public", + description: "Let others see you!", + }, +]; diff --git a/vinvoor/src/util/fetch.ts b/vinvoor/src/util/fetch.ts index dbfe04e..d13ea3c 100644 --- a/vinvoor/src/util/fetch.ts +++ b/vinvoor/src/util/fetch.ts @@ -9,7 +9,7 @@ export const getApi = (endpoint: string, convertData?: (data: any) => T) => { export const postApi = ( endpoint: string, - body: { [key: string]: string } = {} + body: { [key: string]: string | number | boolean } = {} ) => { return _fetch(`${URLS.API}/${endpoint}`, { method: "POST", @@ -20,7 +20,7 @@ export const postApi = ( export const patchApi = ( endpoint: string, - body: { [key: string]: string } = {} + body: { [key: string]: string | number | boolean } = {} ) => { return _fetch(`${URLS.API}/${endpoint}`, { method: "PATCH", From 18d11fbd8f282d32ea68801a7cb23aa979059ce3 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Fri, 19 Jul 2024 01:58:10 +0200 Subject: [PATCH 04/22] vinvoor: make various css improvements --- vinvoor/src/App.tsx | 2 +- vinvoor/src/WelcomePage.tsx | 35 ++- vinvoor/src/cards/CardsDelete.tsx | 12 +- vinvoor/src/cards/CardsTable.tsx | 4 +- vinvoor/src/cards/CardsTableBody.tsx | 2 +- vinvoor/src/cards/CardsTableHead.tsx | 4 +- vinvoor/src/cards/CardsTableToolbar.tsx | 6 +- vinvoor/src/components/DarkModeToggle.tsx | 10 +- vinvoor/src/leaderboard/Leaderboard.tsx | 2 +- .../src/leaderboard/LeaderboardTableBody.tsx | 64 +++-- .../leaderboard/LeaderboardTableToolbar.tsx | 2 +- vinvoor/src/main.tsx | 15 +- vinvoor/src/navbar/NavBar.tsx | 10 +- vinvoor/src/navbar/NavBarLogo.tsx | 27 ++- vinvoor/src/navbar/NavBarPages.tsx | 2 +- vinvoor/src/navbar/NavBarSandwich.tsx | 5 +- vinvoor/src/navbar/NavBarUserMenu.tsx | 31 ++- vinvoor/src/overview/Overview.tsx | 144 ++++++----- vinvoor/src/overview/checkin/CheckIn.tsx | 7 +- vinvoor/src/overview/days/Days.tsx | 28 ++- vinvoor/src/overview/heatmap/Heatmap.tsx | 57 +++-- vinvoor/src/overview/heatmap/heatmap.css | 62 +---- vinvoor/src/overview/heatmap/utils.ts | 35 ++- vinvoor/src/overview/streak/Streak.tsx | 22 +- .../src/providers/CustomSnackbarProvider.tsx | 37 +++ .../{theme => providers}/ThemeProvider.tsx | 22 +- .../src/{user => providers}/UserProvider.tsx | 0 vinvoor/src/scans/ScansTableHead.tsx | 2 +- vinvoor/src/settings/SettingsOverview.tsx | 9 +- vinvoor/src/theme.ts | 229 ++++++++++++++++++ vinvoor/src/theme/theme.ts | 50 ---- vinvoor/src/types/cards.ts | 2 +- vinvoor/src/types/leaderboard.ts | 2 +- vinvoor/src/types/scans.ts | 10 +- vinvoor/src/util/fetch.ts | 6 +- 35 files changed, 631 insertions(+), 326 deletions(-) create mode 100644 vinvoor/src/providers/CustomSnackbarProvider.tsx rename vinvoor/src/{theme => providers}/ThemeProvider.tsx (62%) rename vinvoor/src/{user => providers}/UserProvider.tsx (100%) create mode 100644 vinvoor/src/theme.ts delete mode 100644 vinvoor/src/theme/theme.ts diff --git a/vinvoor/src/App.tsx b/vinvoor/src/App.tsx index 76278d2..e8882c3 100644 --- a/vinvoor/src/App.tsx +++ b/vinvoor/src/App.tsx @@ -4,7 +4,7 @@ import { Navigate, Outlet, useOutlet } from "react-router-dom"; import { LoadingSkeleton } from "./components/LoadingSkeleton"; import { NavBar } from "./navbar/NavBar"; import { Overview } from "./overview/Overview"; -import { UserContext } from "./user/UserProvider"; +import { UserContext } from "./providers/UserProvider"; import { WelcomePage } from "./WelcomePage"; export const App = () => { diff --git a/vinvoor/src/WelcomePage.tsx b/vinvoor/src/WelcomePage.tsx index e4a7e28..ea06511 100644 --- a/vinvoor/src/WelcomePage.tsx +++ b/vinvoor/src/WelcomePage.tsx @@ -29,26 +29,21 @@ export const WelcomePage = () => { > Welcome to Vinvoor! Log in to start scanning - - Log in with Zauth - - - + + + Log in with Zauth + + + + ); }; - -// -// -// diff --git a/vinvoor/src/cards/CardsDelete.tsx b/vinvoor/src/cards/CardsDelete.tsx index fa63fcd..2fd8e29 100644 --- a/vinvoor/src/cards/CardsDelete.tsx +++ b/vinvoor/src/cards/CardsDelete.tsx @@ -1,23 +1,27 @@ import DeleteIcon from "@mui/icons-material/Delete"; import { IconButton, Link, Tooltip, Typography } from "@mui/material"; import { useConfirm } from "material-ui-confirm"; +import { useSnackbar } from "notistack"; import { FC } from "react"; interface CardDeleteProps { selected: readonly string[]; } +const deletePressed = "Not implemented yet :'("; + export const CardsDelete: FC = ({ selected }) => { const confirm = useConfirm(); + const { enqueueSnackbar } = useSnackbar(); const numSelected = selected.length; const title = `Delete card${numSelected > 1 ? "s" : ""}`; const content = ( - - ` Are you sure you want to delete ${numSelected} card$ + + Are you sure you want to delete {numSelected} card {numSelected > 1 ? "s" : ""}? Unfortunately, this feature isn't available yet. Let's convince Hannes to add this feature by signing - this petition!` + this petition! ); @@ -26,7 +30,7 @@ export const CardsDelete: FC = ({ selected }) => { title: title, description: content, confirmationText: "Delete", - }).then(() => console.log("Card deleted!")); + }).then(() => enqueueSnackbar(deletePressed, { variant: "error" })); }; return ( diff --git a/vinvoor/src/cards/CardsTable.tsx b/vinvoor/src/cards/CardsTable.tsx index 512e777..ae828dd 100644 --- a/vinvoor/src/cards/CardsTable.tsx +++ b/vinvoor/src/cards/CardsTable.tsx @@ -20,8 +20,8 @@ const getComparator = ( order: TableOrder, orderBy: Key ): (( - a: { [key in Key]: number | string | Date }, - b: { [key in Key]: number | string | Date } + a: Record, + b: Record ) => number) => { return order === "desc" ? (a, b) => descendingComparator(a, b, orderBy) diff --git a/vinvoor/src/cards/CardsTableBody.tsx b/vinvoor/src/cards/CardsTableBody.tsx index b4659ef..53702b8 100644 --- a/vinvoor/src/cards/CardsTableBody.tsx +++ b/vinvoor/src/cards/CardsTableBody.tsx @@ -77,7 +77,7 @@ export const CardsTableBody: FC = ({ const editButton = (id: number, name: string) => ( handleEditClick(id, name)}> - + ); diff --git a/vinvoor/src/cards/CardsTableHead.tsx b/vinvoor/src/cards/CardsTableHead.tsx index 9c651c0..1604fea 100644 --- a/vinvoor/src/cards/CardsTableHead.tsx +++ b/vinvoor/src/cards/CardsTableHead.tsx @@ -57,7 +57,9 @@ export const CardsTableHead: FC = ({ direction={orderBy === headCell.id ? order : "asc"} onClick={createSortHandler(headCell.id)} > - {headCell.label} + + {headCell.label} + ))} diff --git a/vinvoor/src/cards/CardsTableToolbar.tsx b/vinvoor/src/cards/CardsTableToolbar.tsx index f9dc865..8c55b24 100644 --- a/vinvoor/src/cards/CardsTableToolbar.tsx +++ b/vinvoor/src/cards/CardsTableToolbar.tsx @@ -37,7 +37,11 @@ export const CardsTableToolbar: FC = ({ selected }) => { ) : ( <> - + Cards diff --git a/vinvoor/src/components/DarkModeToggle.tsx b/vinvoor/src/components/DarkModeToggle.tsx index ab4833e..602a635 100644 --- a/vinvoor/src/components/DarkModeToggle.tsx +++ b/vinvoor/src/components/DarkModeToggle.tsx @@ -1,14 +1,13 @@ import { DarkModeOutlined, LightModeOutlined } from "@mui/icons-material"; import { IconButton, Tooltip } from "@mui/material"; import { useContext } from "react"; -import { ThemeContext } from "../theme/ThemeProvider"; +import { ThemeContext } from "../providers/ThemeProvider"; export const DarkModeToggle = () => { - const { themeMode, toggleTheme } = useContext(ThemeContext); + const { themeMode, setTheme } = useContext(ThemeContext); - const handleThemeChange = () => { - toggleTheme(); - }; + const handleThemeChange = () => + setTheme(themeMode === "light" ? "dark" : "light"); return ( { ); }; +`` diff --git a/vinvoor/src/leaderboard/Leaderboard.tsx b/vinvoor/src/leaderboard/Leaderboard.tsx index ca9ebb6..ccd6c94 100644 --- a/vinvoor/src/leaderboard/Leaderboard.tsx +++ b/vinvoor/src/leaderboard/Leaderboard.tsx @@ -20,7 +20,7 @@ export const Leaderboard = () => { diff --git a/vinvoor/src/leaderboard/LeaderboardTableBody.tsx b/vinvoor/src/leaderboard/LeaderboardTableBody.tsx index dcf0999..4c9d6f2 100644 --- a/vinvoor/src/leaderboard/LeaderboardTableBody.tsx +++ b/vinvoor/src/leaderboard/LeaderboardTableBody.tsx @@ -5,16 +5,11 @@ import { TableRow, Typography, } from "@mui/material"; -import { alpha } from "@mui/material/styles"; -import { - ArrowDownBoldHexagonOutline, - ArrowUpBoldHexagonOutline, - Minus, -} from "mdi-material-ui"; +import { alpha, Theme, useTheme } from "@mui/material/styles"; import { FC, useContext } from "react"; +import { UserContext } from "../providers/UserProvider"; import { TableHeadCell } from "../types/general"; import { leaderboardHeadCells, LeaderboardItem } from "../types/leaderboard"; -import { UserContext } from "../user/UserProvider"; import FirstPlaceIcon from "/first_place.svg"; import SecondPlaceIcon from "/second_place.svg"; import ThirdPlaceIcon from "/third_place.svg"; @@ -23,22 +18,41 @@ interface LeaderboardTableBodyProps { leaderboardItems: readonly LeaderboardItem[]; } +const leaderboardColors = [ + (theme: Theme) => theme.leaderboard.first, + (theme: Theme) => theme.leaderboard.second, + (theme: Theme) => theme.leaderboard.third, +]; + +const leaderboardText = [ + { fontSize: "30px", fontWeight: "bold" }, + { fontSize: "25px", fontWeight: "bold" }, + { fontSize: "18px", fontWeight: "bold" }, +]; + +const getLeaderboardColor = (index: number, theme: Theme) => + leaderboardColors[index] + ? { backgroundColor: leaderboardColors[index](theme) } + : {}; + +const getLeaderboardText = (index: number) => leaderboardText[index] || {}; + const getPositionChange = (positionChange: number) => { - let icon: JSX.Element | null = null; + let color = "text.primary"; + let prefix = ""; if (positionChange > 0) { - icon = ; + color = "success.light"; + prefix = "+"; } else if (positionChange < 0) { - icon = ; - } else { - icon = ; + color = "error.light"; } return ( - <> - {icon} - {positionChange} - + + {prefix} + {positionChange !== 0 && positionChange} + ); }; @@ -46,19 +60,19 @@ const getPosition = (position: number) => { switch (position) { case 1: return ( - + ); case 2: return ( - + ); case 3: return ( - + ); @@ -77,13 +91,22 @@ const getCell = ( case "position": return getPosition(row[headCell.id]); default: - return {row[headCell.id]}; + return ( + + {row[headCell.id]} + + ); } }; export const LeaderboardTableBody: FC = ({ leaderboardItems: rows, }) => { + const theme = useTheme(); const { userState: { user }, } = useContext(UserContext); @@ -107,6 +130,7 @@ export const LeaderboardTableBody: FC = ({ theme.palette.action.activatedOpacity ), }), + ...getLeaderboardColor(index, theme), }} > {leaderboardHeadCells.map((headCell) => ( diff --git a/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx b/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx index 44f9103..6d9ff5a 100644 --- a/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx +++ b/vinvoor/src/leaderboard/LeaderboardTableToolbar.tsx @@ -2,7 +2,7 @@ import { MoveDown } from "@mui/icons-material"; import { Button, Toolbar, Typography } from "@mui/material"; import { FC, useContext } from "react"; import { HashLink } from "react-router-hash-link"; -import { UserContext } from "../user/UserProvider"; +import { UserContext } from "../providers/UserProvider"; interface LeaderboardTableToolbarProps {} diff --git a/vinvoor/src/main.tsx b/vinvoor/src/main.tsx index 57bb121..4fb04b4 100644 --- a/vinvoor/src/main.tsx +++ b/vinvoor/src/main.tsx @@ -4,7 +4,6 @@ import "@fontsource/roboto/500.css"; import "@fontsource/roboto/700.css"; import { CssBaseline } from "@mui/material"; import { ConfirmProvider } from "material-ui-confirm"; -import { SnackbarProvider } from "notistack"; import React from "react"; import ReactDOM from "react-dom/client"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; @@ -13,12 +12,13 @@ import { App } from "./App.tsx"; import { Cards } from "./cards/Cards.tsx"; import { ErrorPage } from "./errors/ErrorPage.tsx"; import { Leaderboard } from "./leaderboard/Leaderboard.tsx"; +import { CustomSnackbarProvider } from "./providers/CustomSnackbarProvider.tsx"; +import { ThemeProvider } from "./providers/ThemeProvider.tsx"; +import { UserProvider } from "./providers/UserProvider.tsx"; import { Scans } from "./scans/Scans.tsx"; import { SettingsOverview } from "./settings/SettingsOverview.tsx"; -import { ThemeProvider } from "./theme/ThemeProvider"; import { Login } from "./user/Login.tsx"; import { Logout } from "./user/Logout.tsx"; -import { UserProvider } from "./user/UserProvider.tsx"; const router = createBrowserRouter([ { @@ -60,14 +60,9 @@ ReactDOM.createRoot(document.getElementById("root")!).render( - + - + diff --git a/vinvoor/src/navbar/NavBar.tsx b/vinvoor/src/navbar/NavBar.tsx index cabed2c..b4413da 100644 --- a/vinvoor/src/navbar/NavBar.tsx +++ b/vinvoor/src/navbar/NavBar.tsx @@ -7,7 +7,7 @@ import { } from "mdi-material-ui"; import { useContext } from "react"; import { DarkModeToggle } from "../components/DarkModeToggle"; -import { UserContext } from "../user/UserProvider"; +import { UserContext } from "../providers/UserProvider"; import { NavBarLogo } from "./NavBarLogo"; import { NavBarPages } from "./NavBarPages"; import { NavBarSandwich } from "./NavBarSandwich"; @@ -39,13 +39,7 @@ export const NavBar = () => { }; return ( - + {/* Display either the ZeSS logo or a sandwich menu */} diff --git a/vinvoor/src/navbar/NavBarLogo.tsx b/vinvoor/src/navbar/NavBarLogo.tsx index 015a46d..a89a57e 100644 --- a/vinvoor/src/navbar/NavBarLogo.tsx +++ b/vinvoor/src/navbar/NavBarLogo.tsx @@ -1,22 +1,45 @@ import { Box, Button, SxProps, Theme, Typography } from "@mui/material"; import { HexagonSlice6 } from "mdi-material-ui"; -import { FC } from "react"; +import { FC, useContext } from "react"; import { UnstyledLink } from "../components/UnstyledLink"; +import { ThemeContext } from "../providers/ThemeProvider"; interface NavBarLogoProps { sx?: SxProps; } +const CLICK_AMOUNT = 10; +const CLICK_TIME_MS = 900; + +let pressedAmount = 0; +let startTimePress = 0; + export const NavBarLogo: FC = ({ sx }) => { + const { setTheme } = useContext(ThemeContext); + const handleClick = () => { + if (pressedAmount < CLICK_AMOUNT) { + if (pressedAmount === 0) startTimePress = Date.now(); + + pressedAmount++; + + if ( + pressedAmount === CLICK_AMOUNT && + Date.now() - startTimePress <= CLICK_TIME_MS + ) + setTheme("hidden"); + } + }; + return ( = ({ pageIcons }) => { ))} + {user.admin && ( + + + + Admin + + + )} { + return Admin; +}; diff --git a/vinvoor/yarn.lock b/vinvoor/yarn.lock index 8a3865f..36016bc 100644 --- a/vinvoor/yarn.lock +++ b/vinvoor/yarn.lock @@ -2071,13 +2071,6 @@ react-apexcharts@^1.4.1: dependencies: prop-types "^15.8.1" -react-device-detect@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-2.2.3.tgz#97a7ae767cdd004e7c3578260f48cf70c036e7ca" - integrity sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw== - dependencies: - ua-parser-js "^1.0.33" - react-dom@^18.2.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" @@ -2398,11 +2391,6 @@ typescript@^5.2.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== -ua-parser-js@^1.0.33: - version "1.0.38" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.38.tgz#66bb0c4c0e322fe48edfe6d446df6042e62f25e2" - integrity sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ== - update-browserslist-db@^1.0.16: version "1.1.0" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" From 07b59498ebf9d81069ca385bda20128f4a69a865 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sat, 20 Jul 2024 16:36:22 +0200 Subject: [PATCH 07/22] vingo: make days endpoint use json --- vingo/handlers/days.go | 27 ++++++++++++++------------- vingo/main.go | 4 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/vingo/handlers/days.go b/vingo/handlers/days.go index c4e4fc6..8dd0e6e 100644 --- a/vingo/handlers/days.go +++ b/vingo/handlers/days.go @@ -7,19 +7,21 @@ import ( "github.com/gofiber/fiber/v2" ) -func DaysRegister(c *fiber.Ctx) error { - form_start_date := c.FormValue("start_date") - form_end_date := c.FormValue("end_date") - - start_date, start_err := time.Parse("2006-01-02", form_start_date) - end_date, end_err := time.Parse("2006-01-02", form_end_date) - if start_err != nil || end_err != nil { - logger.Println("Error parsing dates:", start_err, end_err) - return c.Status(400).SendString("Error parsing dates") +type Days struct{} + +type DaysBody struct { + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` +} + +func (Days) CreateMultiple(c *fiber.Ctx) error { + payload := new(DaysBody) + if err := c.BodyParser(payload); err != nil { + logger.Println("Error parsing body:", err) + return c.Status(400).SendString("Error parsing body") } - logger.Println("Registering days from", start_date, "to", end_date) - err := database.CreateDays(start_date, end_date) + err := database.CreateDays(payload.StartDate, payload.EndDate) if err != nil { logger.Println("Error creating days:", err) return c.Status(500).SendString("Error creating days") @@ -28,9 +30,8 @@ func DaysRegister(c *fiber.Ctx) error { return c.Redirect("/days") } -func DaysDelete(c *fiber.Ctx) error { +func (Days) Delete(c *fiber.Ctx) error { day_id := c.Params("id") - logger.Println("Deleting day", day_id) err := database.DeleteDay(day_id) if err != nil { logger.Println("Error deleting day:", err) diff --git a/vingo/main.go b/vingo/main.go index ab8e540..d56e6de 100644 --- a/vingo/main.go +++ b/vingo/main.go @@ -56,8 +56,8 @@ func main() { admin := api.Group("/admin", handlers.IsAdmin) { - admin.Post("/days", handlers.DaysRegister) - admin.Post("/days/:id", handlers.DaysDelete) + admin.Post("/days", handlers.Days{}.CreateMultiple) + admin.Delete("/days/:id", handlers.Days{}.Delete) } } From e3cd90e00a2c22af0bcbce68d4b275a536eb6736 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sat, 20 Jul 2024 16:36:41 +0200 Subject: [PATCH 08/22] vingo: fix settings endpoint --- vingo/database/settings.go | 9 ++++++--- vingo/database/users.go | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/vingo/database/settings.go b/vingo/database/settings.go index c26f98b..777635e 100644 --- a/vingo/database/settings.go +++ b/vingo/database/settings.go @@ -1,14 +1,17 @@ package database +import "log" + func CreateSettings(user_id int) error { _, err := db.Exec("INSERT INTO settings (user_id) VALUES ($1) ON CONFLICT DO NOTHING;", user_id) return err } func GetSettings(user_id int) (*Settings, error) { - var settings Settings - result := gorm_db.First(&settings, "user_id = ?", user_id) - return &settings, result.Error + var user User + result := gorm_db.Preload("Settings").First(&user, user_id) + log.Println(user) + return &user.Settings, result.Error } func UpdateSettings(user_id int, settings Settings) error { diff --git a/vingo/database/users.go b/vingo/database/users.go index 123d93d..c46c9b7 100644 --- a/vingo/database/users.go +++ b/vingo/database/users.go @@ -15,7 +15,7 @@ func CreateUserIfNew(user_id int, username string) error { func GetUser(user_id int) (*User, error) { var user User - result := gorm_db.First(&user, user_id) + result := gorm_db.Preload("Settings").First(&user, user_id) return &user, result.Error } From 51fbb7f9f7adc18312c45f18d1bfb40092699c3b Mon Sep 17 00:00:00 2001 From: Hannes Date: Sat, 20 Jul 2024 17:07:37 +0200 Subject: [PATCH 09/22] vingo: fix settings endpoint --- vingo/database/settings.go | 20 +++++++++++++------- vingo/handlers/settings.go | 7 ++++++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/vingo/database/settings.go b/vingo/database/settings.go index 777635e..b3d284e 100644 --- a/vingo/database/settings.go +++ b/vingo/database/settings.go @@ -2,11 +2,6 @@ package database import "log" -func CreateSettings(user_id int) error { - _, err := db.Exec("INSERT INTO settings (user_id) VALUES ($1) ON CONFLICT DO NOTHING;", user_id) - return err -} - func GetSettings(user_id int) (*Settings, error) { var user User result := gorm_db.Preload("Settings").First(&user, user_id) @@ -15,6 +10,17 @@ func GetSettings(user_id int) (*Settings, error) { } func UpdateSettings(user_id int, settings Settings) error { - _, err := db.Exec("UPDATE settings SET scan_in_out = $1, leaderboard = $2, public = $3 WHERE user_id = $4;", settings.ScanInOut, settings.Leaderboard, settings.Public, user_id) - return err + var user User + if err := gorm_db.Preload("Settings").First(&user, user_id).Error; err != nil { + return err + } + + user.Settings.ScanInOut = settings.ScanInOut + user.Settings.Leaderboard = settings.Leaderboard + user.Settings.Public = settings.Public + if err := gorm_db.Save(&user.Settings).Error; err != nil { + return err + } + + return nil } diff --git a/vingo/handlers/settings.go b/vingo/handlers/settings.go index 4795e50..5627c05 100644 --- a/vingo/handlers/settings.go +++ b/vingo/handlers/settings.go @@ -18,8 +18,13 @@ func (Settings) Update(c *fiber.Ctx) error { return c.Status(400).SendString("Invalid payload") } + err = database.UpdateSettings(user.Id, settings) + if err != nil { + logger.Println(err) + return c.Status(500).SendString("Error updating settings") + } + sess, _ := store.Get(c) - database.UpdateSettings(user.Id, settings) user, _ = database.GetUser(user.Id) sess.Set(STORE_USER, &user) sess.Save() From a8d51b44b88449a09cd8a0415a5dbcb6ae474482 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Sun, 21 Jul 2024 23:35:07 +0200 Subject: [PATCH 10/22] vinvoor: minor visual improvements --- vinvoor/src/cards/CardsAdd.tsx | 49 +++++++++++-------- vinvoor/src/overview/Overview.tsx | 15 ++---- vinvoor/src/overview/heatmap/Heatmap.tsx | 4 +- vinvoor/src/overview/heatmap/heatmap.css | 10 ++-- vinvoor/src/overview/heatmap/utils.ts | 10 +++- .../src/providers/CustomSnackbarProvider.tsx | 2 +- vinvoor/src/settings/SettingsOverview.tsx | 7 +-- vinvoor/src/theme.ts | 11 +++-- 8 files changed, 61 insertions(+), 47 deletions(-) diff --git a/vinvoor/src/cards/CardsAdd.tsx b/vinvoor/src/cards/CardsAdd.tsx index fa5eb00..b64a134 100644 --- a/vinvoor/src/cards/CardsAdd.tsx +++ b/vinvoor/src/cards/CardsAdd.tsx @@ -73,7 +73,7 @@ export const CardsAdd = () => { await postApi(REGISTER_ENDPOINT) .then(() => (started = true)) .catch((error) => { - if (isResponseNot200Error(error)) + if (isResponseNot200Error(error)) { error.response .json() .then((response: CardPostResponse) => { @@ -86,7 +86,7 @@ export const CardsAdd = () => { variant: "error", }); }); - else throw new Error(error); + } else throw new Error(error); }); } @@ -95,29 +95,36 @@ export const CardsAdd = () => { if (started) { setRegistering(true); - const id = randomInt().toString(); - enqueueSnackbar(requestSuccess, { - variant: "info", - persist: true, - key: id, - }); + let id: string | undefined; + + if (!(response.registering && response.isCurrentUser)) { + id = randomInt().toString(); + enqueueSnackbar(requestSuccess, { + variant: "info", + persist: true, + key: id, + }); + } checkCardsChange() .then((scanned) => { - closeSnackbar(id); setRegistering(false); - if (scanned) { - enqueueSnackbar(registerSucces, { - variant: "success", - }); - getApi( - "cards", - convertCardJSON - ).then((cards) => setCards(cards)); - } else - enqueueSnackbar(registerFail, { - variant: "error", - }); + if (id) { + closeSnackbar(id); + + if (scanned) { + enqueueSnackbar(registerSucces, { + variant: "success", + }); + getApi( + "cards", + convertCardJSON + ).then((cards) => setCards(cards)); + } else + enqueueSnackbar(registerFail, { + variant: "error", + }); + } }) .finally(() => setProgressProps(defaultProgressProps)); } diff --git a/vinvoor/src/overview/Overview.tsx b/vinvoor/src/overview/Overview.tsx index 76897dc..61377c6 100644 --- a/vinvoor/src/overview/Overview.tsx +++ b/vinvoor/src/overview/Overview.tsx @@ -50,12 +50,7 @@ export const Overview = () => { {scans.length > 0 ? ( - + @@ -88,8 +83,8 @@ export const Overview = () => { { ); }; - -// Current height of the heatmap is calculated using ref's and calculus -// TODO: Change it as it is very very very very very very ugly ^^ -// Add a grid item underneath and see what happens diff --git a/vinvoor/src/overview/heatmap/Heatmap.tsx b/vinvoor/src/overview/heatmap/Heatmap.tsx index e2bcdea..e09ce90 100644 --- a/vinvoor/src/overview/heatmap/Heatmap.tsx +++ b/vinvoor/src/overview/heatmap/Heatmap.tsx @@ -271,7 +271,9 @@ export const Heatmap: FC = ({ {renderMonthLabels()} - + {renderColumns()} diff --git a/vinvoor/src/overview/heatmap/heatmap.css b/vinvoor/src/overview/heatmap/heatmap.css index 56673ed..6bb2a2f 100644 --- a/vinvoor/src/overview/heatmap/heatmap.css +++ b/vinvoor/src/overview/heatmap/heatmap.css @@ -2,11 +2,6 @@ stroke-opacity: 0; } -.rect { - animation: createBox 1s; - stroke-width: 1px; -} - @keyframes createBox { from { width: 0; @@ -16,3 +11,8 @@ transform: scale(1); } } + +.rect { + /* animation: createBox 1s; */ + stroke-width: 1px; +} diff --git a/vinvoor/src/overview/heatmap/utils.ts b/vinvoor/src/overview/heatmap/utils.ts index 780689f..b427295 100644 --- a/vinvoor/src/overview/heatmap/utils.ts +++ b/vinvoor/src/overview/heatmap/utils.ts @@ -88,8 +88,16 @@ export const getColumnCount = ( variant: HeatmapVariant ) => { if (variant === HeatmapVariant.DAYS) { + const startOfWeek = new Date(startDate); + startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay()); + + const endOfWeek = new Date(endDate); + if (endOfWeek.getDay() === 0) + endOfWeek.setDate(endOfWeek.getDate() - endOfWeek.getDay()); + else endOfWeek.setDate(endOfWeek.getDate() - endOfWeek.getDay() + 6); + return Math.ceil( - (endDate.getTime() - startDate.getTime()) / + (endOfWeek.getTime() - startOfWeek.getTime()) / (DAYS_IN_WEEK * MILLISECONDS_IN_ONE_DAY) ); } else { diff --git a/vinvoor/src/providers/CustomSnackbarProvider.tsx b/vinvoor/src/providers/CustomSnackbarProvider.tsx index 144bb63..a6f7fe5 100644 --- a/vinvoor/src/providers/CustomSnackbarProvider.tsx +++ b/vinvoor/src/providers/CustomSnackbarProvider.tsx @@ -24,7 +24,7 @@ export const CustomSnackbarProvider: FC = ({ { - More settings coming soon! - + ...yay? + diff --git a/vinvoor/src/theme.ts b/vinvoor/src/theme.ts index 95509b1..82b12e2 100644 --- a/vinvoor/src/theme.ts +++ b/vinvoor/src/theme.ts @@ -2,9 +2,6 @@ import { createTheme, ThemeOptions } from "@mui/material"; const baseTheme: ThemeOptions = { palette: { - primary: { - main: "#ff7f00", - }, secondary: { main: "#002379", }, @@ -48,6 +45,10 @@ export const lightTheme = createTheme({ palette: { ...baseTheme.palette, mode: "light", + primary: { + main: "#ff7f00", + contrastText: "#121212", + }, }, }); @@ -56,6 +57,10 @@ export const darkTheme = createTheme({ palette: { ...baseTheme.palette, mode: "dark", + primary: { + main: "#ff7f00", + contrastText: "#ffffff", + }, background: { default: "#121212", }, From 31bc3ddbb45b036c5611d043ad7ff4e234f97fbb Mon Sep 17 00:00:00 2001 From: Topvennie Date: Mon, 22 Jul 2024 00:19:31 +0200 Subject: [PATCH 11/22] vinvoor: add an admin page --- vinvoor/package.json | 2 + vinvoor/src/settings/admin/Admin.tsx | 90 ++- vinvoor/yarn.lock | 922 ++++++++++++++------------- 3 files changed, 560 insertions(+), 454 deletions(-) diff --git a/vinvoor/package.json b/vinvoor/package.json index 20ea43d..95435df 100644 --- a/vinvoor/package.json +++ b/vinvoor/package.json @@ -16,10 +16,12 @@ "@fontsource/roboto": "^5.0.13", "@mui/icons-material": "^5.15.19", "@mui/material": "^5.15.19", + "@mui/x-date-pickers": "^7.11.0", "@types/js-cookie": "^3.0.6", "@types/react-router-dom": "^5.3.3", "@types/react-router-hash-link": "^2.4.9", "apexcharts": "^3.50.0", + "dayjs": "^1.11.12", "js-cookie": "^3.0.5", "material-ui-confirm": "^3.0.16", "mdi-material-ui": "^7.9.1", diff --git a/vinvoor/src/settings/admin/Admin.tsx b/vinvoor/src/settings/admin/Admin.tsx index c181dea..f909c7c 100644 --- a/vinvoor/src/settings/admin/Admin.tsx +++ b/vinvoor/src/settings/admin/Admin.tsx @@ -1,6 +1,90 @@ -import { Typography } from "@mui/material"; -import { FC } from "react"; +import { Box, Button, Grid, Paper, Stack, Typography } from "@mui/material"; +import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import dayjs, { Dayjs } from "dayjs"; +import { useSnackbar } from "notistack"; +import { Dispatch, FC, SetStateAction, useState } from "react"; +import { postApi } from "../../util/fetch"; export const Admin: FC = () => { - return Admin; + const [startDate, setStartDate] = useState(dayjs()); + const [endDate, setEndDate] = useState(dayjs()); + + const { enqueueSnackbar } = useSnackbar(); + + const handleDateChange = ( + date: Dayjs | null, + setter: Dispatch> + ) => setter(date); + + const handleOnClick = () => { + if (!startDate || !endDate) { + enqueueSnackbar("Please select a start and end date", { + variant: "error", + }); + return; + } + + postApi("admin/days", { + start_date: startDate.toISOString(), + end_date: endDate.toISOString(), + }) + .then(() => + enqueueSnackbar("successfully saved days", { + variant: "success", + }) + ) + .catch((error) => + // This is the admin page so just show the error + enqueueSnackbar(`Failed to save days: ${error}`, { + variant: "error", + }) + ); + }; + + return ( + + + + + Set days + + + + handleDateChange(newValue, setStartDate) + } + /> + + handleDateChange(newValue, setEndDate) + } + /> + + + + + + + + + + ); }; diff --git a/vinvoor/yarn.lock b/vinvoor/yarn.lock index 36016bc..fc0db07 100644 --- a/vinvoor/yarn.lock +++ b/vinvoor/yarn.lock @@ -18,50 +18,50 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" - integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== +"@babel/compat-data@^7.24.8": + version "7.24.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.9.tgz#53eee4e68f1c1d0282aa0eb05ddb02d033fc43a0" + integrity sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng== "@babel/core@^7.21.3": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" - integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== + version "7.24.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.9.tgz#dc07c9d307162c97fa9484ea997ade65841c7c82" + integrity sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-compilation-targets" "^7.24.7" - "@babel/helper-module-transforms" "^7.24.7" - "@babel/helpers" "^7.24.7" - "@babel/parser" "^7.24.7" + "@babel/generator" "^7.24.9" + "@babel/helper-compilation-targets" "^7.24.8" + "@babel/helper-module-transforms" "^7.24.9" + "@babel/helpers" "^7.24.8" + "@babel/parser" "^7.24.8" "@babel/template" "^7.24.7" - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/traverse" "^7.24.8" + "@babel/types" "^7.24.9" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" - integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== +"@babel/generator@^7.24.8", "@babel/generator@^7.24.9": + version "7.24.10" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.10.tgz#a4ab681ec2a78bbb9ba22a3941195e28a81d8e76" + integrity sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.9" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" - integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== +"@babel/helper-compilation-targets@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz#b607c3161cd9d1744977d4f97139572fe778c271" + integrity sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw== dependencies: - "@babel/compat-data" "^7.24.7" - "@babel/helper-validator-option" "^7.24.7" - browserslist "^4.22.2" + "@babel/compat-data" "^7.24.8" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" @@ -95,10 +95,10 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helper-module-transforms@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" - integrity sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ== +"@babel/helper-module-transforms@^7.24.9": + version "7.24.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz#e13d26306b89eea569180868e652e7f514de9d29" + integrity sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw== dependencies: "@babel/helper-environment-visitor" "^7.24.7" "@babel/helper-module-imports" "^7.24.7" @@ -121,28 +121,28 @@ dependencies: "@babel/types" "^7.24.7" -"@babel/helper-string-parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" - integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== -"@babel/helper-validator-option@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" - integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== -"@babel/helpers@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" - integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== +"@babel/helpers@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.8.tgz#2820d64d5d6686cca8789dd15b074cd862795873" + integrity sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ== dependencies: "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.8" "@babel/highlight@^7.24.7": version "7.24.7" @@ -154,15 +154,15 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" - integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== +"@babel/parser@^7.24.7", "@babel/parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.8.tgz#58a4dbbcad7eb1d48930524a3fd93d93e9084c6f" + integrity sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w== -"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" - integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== +"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.8.tgz#5d958c3827b13cc6d05e038c07fb2e5e3420d82e" + integrity sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA== dependencies: regenerator-runtime "^0.14.0" @@ -175,41 +175,41 @@ "@babel/parser" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/traverse@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" - integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== +"@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.8.tgz#6c14ed5232b7549df3371d820fbd9abfcd7dfab7" + integrity sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ== dependencies: "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" + "@babel/generator" "^7.24.8" "@babel/helper-environment-visitor" "^7.24.7" "@babel/helper-function-name" "^7.24.7" "@babel/helper-hoist-variables" "^7.24.7" "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/parser" "^7.24.8" + "@babel/types" "^7.24.8" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.21.3", "@babel/types@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" - integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== +"@babel/types@^7.21.3", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.24.9": + version "7.24.9" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.9.tgz#228ce953d7b0d16646e755acf204f4cf3d08cc73" + integrity sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ== dependencies: - "@babel/helper-string-parser" "^7.24.7" + "@babel/helper-string-parser" "^7.24.8" "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" -"@emotion/babel-plugin@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" - integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== +"@emotion/babel-plugin@^11.12.0": + version "11.12.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2" + integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw== dependencies: "@babel/helper-module-imports" "^7.16.7" "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/serialize" "^1.1.2" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/serialize" "^1.2.0" babel-plugin-macros "^3.1.0" convert-source-map "^1.5.0" escape-string-regexp "^4.0.0" @@ -217,95 +217,95 @@ source-map "^0.5.7" stylis "4.2.0" -"@emotion/cache@^11.11.0": - version "11.11.0" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" - integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== +"@emotion/cache@^11.11.0", "@emotion/cache@^11.13.0": + version "11.13.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.0.tgz#8f51748b8116691dee0408b08ad758b8d246b097" + integrity sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g== dependencies: - "@emotion/memoize" "^0.8.1" - "@emotion/sheet" "^1.2.2" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" + "@emotion/memoize" "^0.9.0" + "@emotion/sheet" "^1.4.0" + "@emotion/utils" "^1.4.0" + "@emotion/weak-memoize" "^0.4.0" stylis "4.2.0" -"@emotion/hash@^0.9.1": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" - integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== +"@emotion/hash@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" + integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== -"@emotion/is-prop-valid@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" - integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw== +"@emotion/is-prop-valid@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz#bd84ba972195e8a2d42462387581560ef780e4e2" + integrity sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ== dependencies: - "@emotion/memoize" "^0.8.1" + "@emotion/memoize" "^0.9.0" -"@emotion/memoize@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" - integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== +"@emotion/memoize@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" + integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== "@emotion/react@^11.11.4": - version "11.11.4" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.4.tgz#3a829cac25c1f00e126408fab7f891f00ecc3c1d" - integrity sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw== + version "11.13.0" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.0.tgz#a9ebf827b98220255e5760dac89fa2d38ca7b43d" + integrity sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.11.0" - "@emotion/cache" "^11.11.0" - "@emotion/serialize" "^1.1.3" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@emotion/utils" "^1.2.1" - "@emotion/weak-memoize" "^0.3.1" + "@emotion/babel-plugin" "^11.12.0" + "@emotion/cache" "^11.13.0" + "@emotion/serialize" "^1.3.0" + "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" + "@emotion/utils" "^1.4.0" + "@emotion/weak-memoize" "^0.4.0" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3", "@emotion/serialize@^1.1.4": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451" - integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ== +"@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.0.tgz#e07cadfc967a4e7816e0c3ffaff4c6ce05cb598d" + integrity sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA== dependencies: - "@emotion/hash" "^0.9.1" - "@emotion/memoize" "^0.8.1" - "@emotion/unitless" "^0.8.1" - "@emotion/utils" "^1.2.1" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/unitless" "^0.9.0" + "@emotion/utils" "^1.4.0" csstype "^3.0.2" -"@emotion/sheet@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" - integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== +"@emotion/sheet@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" + integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== "@emotion/styled@^11.11.5": - version "11.11.5" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.5.tgz#0c5c8febef9d86e8a926e663b2e5488705545dfb" - integrity sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ== + version "11.13.0" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.13.0.tgz#633fd700db701472c7a5dbef54d6f9834e9fb190" + integrity sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.11.0" - "@emotion/is-prop-valid" "^1.2.2" - "@emotion/serialize" "^1.1.4" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" - "@emotion/utils" "^1.2.1" - -"@emotion/unitless@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" - integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== - -"@emotion/use-insertion-effect-with-fallbacks@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" - integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw== + "@emotion/babel-plugin" "^11.12.0" + "@emotion/is-prop-valid" "^1.3.0" + "@emotion/serialize" "^1.3.0" + "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" + "@emotion/utils" "^1.4.0" + +"@emotion/unitless@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.9.0.tgz#8e5548f072bd67b8271877e51c0f95c76a66cbe2" + integrity sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ== + +"@emotion/use-insertion-effect-with-fallbacks@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf" + integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== -"@emotion/utils@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" - integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== +"@emotion/utils@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.0.tgz#262f1d02aaedb2ec91c83a0955dd47822ad5fbdd" + integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ== -"@emotion/weak-memoize@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" - integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== +"@emotion/weak-memoize@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" + integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== "@esbuild/aix-ppc64@0.21.5": version "0.21.5" @@ -525,9 +525,9 @@ integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" @@ -537,7 +537,7 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@mui/base@5.0.0-beta.40": +"@mui/base@^5.0.0-beta.40": version "5.0.0-beta.40" resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.40.tgz#1f8a782f1fbf3f84a961e954c8176b187de3dae2" integrity sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ== @@ -550,83 +550,98 @@ clsx "^2.1.0" prop-types "^15.8.1" -"@mui/core-downloads-tracker@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.0.tgz#50153c698e321793c83a0283d8d7a9dc5d43858a" - integrity sha512-8SLffXYPRVpcZx5QzxNE8fytTqzp+IuU3deZbQWg/vSaTlDpR5YVrQ4qQtXTi5cRdhOufV5INylmwlKK+//nPw== +"@mui/core-downloads-tracker@^5.16.4": + version "5.16.4" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz#a34de72acd7e81fdbcc7eeb07786205e90dda148" + integrity sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w== "@mui/icons-material@^5.15.19": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.0.tgz#5269fda922fe5e6db3577ec497e8b987195606ef" - integrity sha512-6ISoOhkp9w5gD0PEW9JklrcbyARDkFWNTBdwXZ1Oy5IGlyu9B0zG0hnUIe4H17IaF1Vgj6C8VI+v4tkSdK0veg== + version "5.16.4" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.4.tgz#8c7e228c1e178992d89fab47e057222c8209bd7b" + integrity sha512-j9/CWctv6TH6Dou2uR2EH7UOgu79CW/YcozxCYVLJ7l03pCsiOlJ5sBArnWJxJ+nGkFwyL/1d1k8JEPMDR125A== dependencies: "@babel/runtime" "^7.23.9" "@mui/material@^5.15.19": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.0.tgz#2ef4f52ae773574fc0a681f25705f376f5cd13f7" - integrity sha512-DbR1NckTLpjt9Zut9EGQ70th86HfN0BYQgyYro6aXQrNfjzSwe3BJS1AyBQ5mJ7TdL6YVRqohfukxj9JlqZZUg== + version "5.16.4" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.4.tgz#992d630637d9d38620e4937fb11d0a97965fdabf" + integrity sha512-dBnh3/zRYgEVIS3OE4oTbujse3gifA0qLMmuUk13ywsDCbngJsdgwW5LuYeiT5pfA8PGPGSqM7mxNytYXgiMCw== dependencies: "@babel/runtime" "^7.23.9" - "@mui/base" "5.0.0-beta.40" - "@mui/core-downloads-tracker" "^5.16.0" - "@mui/system" "^5.16.0" - "@mui/types" "^7.2.14" - "@mui/utils" "^5.16.0" + "@mui/core-downloads-tracker" "^5.16.4" + "@mui/system" "^5.16.4" + "@mui/types" "^7.2.15" + "@mui/utils" "^5.16.4" + "@popperjs/core" "^2.11.8" "@types/react-transition-group" "^4.4.10" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" - react-is "^18.2.0" + react-is "^18.3.1" react-transition-group "^4.4.5" -"@mui/private-theming@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.0.tgz#c1abfd3e0d9c95459048240ef4209dc7f25dc949" - integrity sha512-sYpubkO1MZOnxNyVOClrPNOTs0MfuRVVnAvCeMaOaXt6GimgQbnUcshYv2pSr6PFj+Mqzdff/FYOBceK8u5QgA== +"@mui/private-theming@^5.16.4": + version "5.16.4" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.4.tgz#0118f137975b35dc4774c6d593b8fcf86594c3fc" + integrity sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA== dependencies: "@babel/runtime" "^7.23.9" - "@mui/utils" "^5.16.0" + "@mui/utils" "^5.16.4" prop-types "^15.8.1" -"@mui/styled-engine@^5.15.14": - version "5.15.14" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.14.tgz#168b154c4327fa4ccc1933a498331d53f61c0de2" - integrity sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw== +"@mui/styled-engine@^5.16.4": + version "5.16.4" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.16.4.tgz#a7a8c9079c307bab91ccd65ed5dd1496ddf2a3ab" + integrity sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA== dependencies: "@babel/runtime" "^7.23.9" "@emotion/cache" "^11.11.0" csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.0.tgz#e5b4cfbdfbc0ee9859f6b168e8b07d750303b7a0" - integrity sha512-9YbkC2m3+pNumAvubYv+ijLtog6puJ0fJ6rYfzfLCM47pWrw3m+30nXNM8zMgDaKL6vpfWJcCXm+LPaWBpy7sw== +"@mui/system@^5.16.2", "@mui/system@^5.16.4": + version "5.16.4" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.4.tgz#c03f971ed273f0ad06c69c949c05e866ad211407" + integrity sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w== dependencies: "@babel/runtime" "^7.23.9" - "@mui/private-theming" "^5.16.0" - "@mui/styled-engine" "^5.15.14" - "@mui/types" "^7.2.14" - "@mui/utils" "^5.16.0" + "@mui/private-theming" "^5.16.4" + "@mui/styled-engine" "^5.16.4" + "@mui/types" "^7.2.15" + "@mui/utils" "^5.16.4" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" -"@mui/types@^7.2.14": - version "7.2.14" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.14.tgz#8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9" - integrity sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ== +"@mui/types@^7.2.14", "@mui/types@^7.2.15": + version "7.2.15" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.15.tgz#dadd232fe9a70be0d526630675dff3b110f30b53" + integrity sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q== -"@mui/utils@^5.15.14", "@mui/utils@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.0.tgz#3963127d9a619c251e5be1aef9adab0e89d3e7df" - integrity sha512-kLLi5J1xY+mwtUlMb8Ubdxf4qFAA1+U7WPBvjM/qQ4CIwLCohNb0sHo1oYPufjSIH/Z9+dhVxD7dJlfGjd1AVA== +"@mui/utils@^5.15.14", "@mui/utils@^5.16.2", "@mui/utils@^5.16.4": + version "5.16.4" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.4.tgz#8e50e27a630e3d8eeb3e9d3bc31cbb0e4956f5fd" + integrity sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg== dependencies: "@babel/runtime" "^7.23.9" - "@types/prop-types" "^15.7.11" + "@types/prop-types" "^15.7.12" + clsx "^2.1.1" + prop-types "^15.8.1" + react-is "^18.3.1" + +"@mui/x-date-pickers@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-7.11.0.tgz#ac98d9057b733ddec117bc0938f364316eb12b5a" + integrity sha512-+zPWs1dwe7J1nZ2iFhTgCae31BLMYMQ2VtQfHxx21Dh6gbBRy/U7YJZg1LdhfQyE093S3e4A5uMZ6PUWdne7iA== + dependencies: + "@babel/runtime" "^7.24.8" + "@mui/base" "^5.0.0-beta.40" + "@mui/system" "^5.16.2" + "@mui/utils" "^5.16.2" + "@types/react-transition-group" "^4.4.10" + clsx "^2.1.1" prop-types "^15.8.1" - react-is "^18.2.0" + react-transition-group "^4.4.5" "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -654,10 +669,10 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== -"@remix-run/router@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.17.1.tgz#bf93997beb81863fde042ebd05013a2618471362" - integrity sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q== +"@remix-run/router@1.18.0": + version "1.18.0" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.18.0.tgz#20b033d1f542a100c1d57cfd18ecf442d1784732" + integrity sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw== "@rollup/pluginutils@^5.0.5": version "5.1.0" @@ -668,85 +683,85 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27" - integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ== - -"@rollup/rollup-android-arm64@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203" - integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA== - -"@rollup/rollup-darwin-arm64@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096" - integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w== - -"@rollup/rollup-darwin-x64@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz#e07d76de1cec987673e7f3d48ccb8e106d42c05c" - integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA== - -"@rollup/rollup-linux-arm-gnueabihf@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8" - integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA== - -"@rollup/rollup-linux-arm-musleabihf@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549" - integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A== - -"@rollup/rollup-linux-arm64-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577" - integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw== - -"@rollup/rollup-linux-arm64-musl@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c" - integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ== - -"@rollup/rollup-linux-powerpc64le-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf" - integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA== - -"@rollup/rollup-linux-riscv64-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9" - integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg== - -"@rollup/rollup-linux-s390x-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec" - integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg== - -"@rollup/rollup-linux-x64-gnu@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942" - integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w== - -"@rollup/rollup-linux-x64-musl@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d" - integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg== - -"@rollup/rollup-win32-arm64-msvc@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf" - integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA== - -"@rollup/rollup-win32-ia32-msvc@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54" - integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg== - -"@rollup/rollup-win32-x64-msvc@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4" - integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g== +"@rollup/rollup-android-arm-eabi@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.0.tgz#3d9fd50164b94964f5de68c3c4ce61933b3a338d" + integrity sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w== + +"@rollup/rollup-android-arm64@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.0.tgz#e1a6d4bca2eb08c84fd996a4bf896ce4b6f4014c" + integrity sha512-RDxUSY8D1tWYfn00DDi5myxKgOk6RvWPxhmWexcICt/MEC6yEMr4HNCu1sXXYLw8iAsg0D44NuU+qNq7zVWCrw== + +"@rollup/rollup-darwin-arm64@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.0.tgz#0a3fffea69489a24a96079af414b0be78df8abbc" + integrity sha512-emvKHL4B15x6nlNTBMtIaC9tLPRpeA5jMvRLXVbl/W9Ie7HhkrE7KQjvgS9uxgatL1HmHWDXk5TTS4IaNJxbAA== + +"@rollup/rollup-darwin-x64@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.0.tgz#13fbdb15f58f090871b0ffff047ece06ad6ad74c" + integrity sha512-fO28cWA1dC57qCd+D0rfLC4VPbh6EOJXrreBmFLWPGI9dpMlER2YwSPZzSGfq11XgcEpPukPTfEVFtw2q2nYJg== + +"@rollup/rollup-linux-arm-gnueabihf@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.0.tgz#e9d9219ddf6f6e946e2ee322198af12466d2c868" + integrity sha512-2Rn36Ubxdv32NUcfm0wB1tgKqkQuft00PtM23VqLuCUR4N5jcNWDoV5iBC9jeGdgS38WK66ElncprqgMUOyomw== + +"@rollup/rollup-linux-arm-musleabihf@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.0.tgz#4ba804a00b5e793196a622f6977e05f23e01f59a" + integrity sha512-gJuzIVdq/X1ZA2bHeCGCISe0VWqCoNT8BvkQ+BfsixXwTOndhtLUpOg0A1Fcx/+eA6ei6rMBzlOz4JzmiDw7JQ== + +"@rollup/rollup-linux-arm64-gnu@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.0.tgz#d871e3f41de759a6db27fc99235b782ba47c15cc" + integrity sha512-0EkX2HYPkSADo9cfeGFoQ7R0/wTKb7q6DdwI4Yn/ULFE1wuRRCHybxpl2goQrx4c/yzK3I8OlgtBu4xvted0ug== + +"@rollup/rollup-linux-arm64-musl@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.0.tgz#6e63f7ad4cc51bd2c693a2826fd279de9eaa05b5" + integrity sha512-GlIQRj9px52ISomIOEUq/IojLZqzkvRpdP3cLgIE1wUWaiU5Takwlzpz002q0Nxxr1y2ZgxC2obWxjr13lvxNQ== + +"@rollup/rollup-linux-powerpc64le-gnu@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.0.tgz#1540b284d91c440bc9fa7a1714cfb71a5597e94d" + integrity sha512-N6cFJzssruDLUOKfEKeovCKiHcdwVYOT1Hs6dovDQ61+Y9n3Ek4zXvtghPPelt6U0AH4aDGnDLb83uiJMkWYzQ== + +"@rollup/rollup-linux-riscv64-gnu@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.0.tgz#70ae58103b5bc7ba2e2235738b51d97022c8ef92" + integrity sha512-2DnD3mkS2uuam/alF+I7M84koGwvn3ZVD7uG+LEWpyzo/bq8+kKnus2EVCkcvh6PlNB8QPNFOz6fWd5N8o1CYg== + +"@rollup/rollup-linux-s390x-gnu@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.0.tgz#579ca5f271421a961d3c73d221202c79e02ff03a" + integrity sha512-D6pkaF7OpE7lzlTOFCB2m3Ngzu2ykw40Nka9WmKGUOTS3xcIieHe82slQlNq69sVB04ch73thKYIWz/Ian8DUA== + +"@rollup/rollup-linux-x64-gnu@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.0.tgz#f0282d761b8b4e7b92b236813475248e37231849" + integrity sha512-HBndjQLP8OsdJNSxpNIN0einbDmRFg9+UQeZV1eiYupIRuZsDEoeGU43NQsS34Pp166DtwQOnpcbV/zQxM+rWA== + +"@rollup/rollup-linux-x64-musl@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.0.tgz#65da807ac66c505ad14b76f1e5976006cb67dd5f" + integrity sha512-HxfbvfCKJe/RMYJJn0a12eiOI9OOtAUF4G6ozrFUK95BNyoJaSiBjIOHjZskTUffUrB84IPKkFG9H9nEvJGW6A== + +"@rollup/rollup-win32-arm64-msvc@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.0.tgz#1eed24b91f421c2eea8bb7ca8889ba0c867e1780" + integrity sha512-HxDMKIhmcguGTiP5TsLNolwBUK3nGGUEoV/BO9ldUBoMLBssvh4J0X8pf11i1fTV7WShWItB1bKAKjX4RQeYmg== + +"@rollup/rollup-win32-ia32-msvc@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.0.tgz#1ed93c9cdc84e185359797a686f4d1576afcea58" + integrity sha512-xItlIAZZaiG/u0wooGzRsx11rokP4qyc/79LkAOdznGRAbOFc+SfEdfUOszG1odsHNgwippUJavag/+W/Etc6Q== + +"@rollup/rollup-win32-x64-msvc@4.19.0": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.0.tgz#baf9b65023ea2ecc5e6ec68f787a0fecfd8ee84c" + integrity sha512-xNo5fV5ycvCCKqiZcpB65VMR11NJB+StnxHz20jdqRAktfdfzhgjTiJ2doTDQE/7dqGaV5I7ZGqKpgph6lCIag== "@svgr/babel-plugin-add-jsx-attribute@8.0.0": version "8.0.0" @@ -831,74 +846,74 @@ "@svgr/hast-util-to-babel-ast" "8.0.0" svg-parser "^2.0.4" -"@swc/core-darwin-arm64@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.7.tgz#e98a0da9635297728a97faf7f4e11c46f8dfbb46" - integrity sha512-sNb+ghP2OhZyUjS7E5Mf3PqSvoXJ5gY6GBaH2qp8WQxx9VL7ozC4HVo6vkeFJBN5cmYqUCLnhrM3HU4W+7yMSA== - -"@swc/core-darwin-x64@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.6.7.tgz#fccd389046a8fe0d8b294f9657b3861046fcd3bb" - integrity sha512-LQwYm/ATYN5fYSYVPMfComPiFo5i8jh75h1ASvNWhXtS+/+k1dq1zXTJWZRuojd5NXgW3bb6mJtJ2evwYIgYbA== - -"@swc/core-linux-arm-gnueabihf@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.6.7.tgz#f384235e5f14870646157017eb06dfbaed0894c0" - integrity sha512-kEDzVhNci38LX3kdY99t68P2CDf+2QFDk5LawVamXH0iN5DRAO/+wjOhxL8KOHa6wQVqKEt5WrhD+Rrvk/34Yw== - -"@swc/core-linux-arm64-gnu@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.6.7.tgz#d2b8c0c6045eecb96bc3f3dfa7fb31b5ab708cdf" - integrity sha512-SyOBUGfl31xLGpIJ/Jd6GKHtkfZyHBXSwFlK7FmPN//MBQLtTBm4ZaWTnWnGo4aRsJwQdXWDKPyqlMBtnIl1nQ== - -"@swc/core-linux-arm64-musl@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.6.7.tgz#6ae2a160ba535b1f4747d35a124f410545092abe" - integrity sha512-1fOAXkDFbRfItEdMZPxT3du1QWYhgToa4YsnqTujjE8EqJW8K27hIcHRIkVuzp7PNhq8nLBg0JpJM4g27EWD7g== - -"@swc/core-linux-x64-gnu@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.6.7.tgz#6ebcf76fa868321c3b079e5c668c137b9b91df49" - integrity sha512-Gp7uCwPsNO5ATxbyvfTyeNCHUGD9oA+xKMm43G1tWCy+l07gLqWMKp7DIr3L3qPD05TfAVo3OuiOn2abpzOFbw== - -"@swc/core-linux-x64-musl@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.6.7.tgz#41531ef3e1c7123d87b7a7a1b984fa2689032621" - integrity sha512-QeruGBZJ15tadqEMQ77ixT/CYGk20MtlS8wmvJiV+Wsb8gPW5LgCjtupzcLLnoQzDG54JGNCeeZ0l/T8NYsOvA== - -"@swc/core-win32-arm64-msvc@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.6.7.tgz#af0b84a54d01bc3aad12acffa98ebb13fc03c3e6" - integrity sha512-ouRqgSnT95lTCiU/6kJRNS5b1o+p8I/V9jxtL21WUj/JOVhsFmBErqQ0MZyCu514noWiR5BIqOrZXR8C1Knx6Q== - -"@swc/core-win32-ia32-msvc@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.6.7.tgz#c454851c05c26f67d2edc399e1cde9d074744ce4" - integrity sha512-eZAP/EmJ0IcfgAx6B4/SpSjq3aT8gr0ooktfMqw/w0/5lnNrbMl2v+2kvxcneNcF7bp8VNcYZnoHlsP+LvmVbA== - -"@swc/core-win32-x64-msvc@1.6.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.6.7.tgz#6ee4a3caf3466971e6b5fb2fba4674924507a2de" - integrity sha512-QOdE+7GQg1UQPS6p0KxzJOh/8GLbJ5zI1vqKArCCB0unFqUfKIjYb2TaH0geEBy3w9qtXxe3ZW6hzxtZSS9lDg== +"@swc/core-darwin-arm64@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.0.tgz#fdc694dd6e8543f3efea0619a6fba9ce82939205" + integrity sha512-2ylhM7f0HwUwLrFYZAe/dse8PCbPsYcJS3Dt7Q8NT3PUn7vy6QOMxNcOPPuDrnmaXqQQO3oxdmRapguTxaat9g== + +"@swc/core-darwin-x64@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.0.tgz#a9a78ace5c7e43c8cb68d11c53d33a0bf966ca8e" + integrity sha512-SgVnN4gT1Rb9YfTkp4FCUITqSs7Yj0uB2SUciu5CV3HuGvS5YXCUzh+KrwpLFtx8NIgivISKcNnb41mJi98X8Q== + +"@swc/core-linux-arm-gnueabihf@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.0.tgz#6861ac82fda01b68b44970d3b9aaa955d7311d98" + integrity sha512-+Z9Dayart1iKJQEJJ9N/KS4z5EdXJE3WPFikY0jonKTo4Dd8RuyVz5yLvqcIMeVdz/SwximATaL6iJXw7hZS9A== + +"@swc/core-linux-arm64-gnu@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.0.tgz#aa0e3dac17807c73d501f52526115666d60ea7a6" + integrity sha512-UnLrCiZ1EI4shznJn0xP6DLgsXUSwtfsdgHhGYCrvbgVBBve3S9iFgVFEB3SPl7Q/TdowNbrN4zHU0oChfiNfw== + +"@swc/core-linux-arm64-musl@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.0.tgz#4bb226a4e9eabac4e1a3b3ffd7ea5955629c84ed" + integrity sha512-H724UANA+ptsfwKRr9mnaDa9cb5fw0oFysiGKTgb3DMYcgk3Od0jMTnXVPFSVpo7FlmyxeC9K8ueUPBOoOK6XA== + +"@swc/core-linux-x64-gnu@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.0.tgz#ee65d1362214e91de89414f41b3310ba5302c2c5" + integrity sha512-SY3HA0K0Dpqt1HIfMLGpwL4hd4UaL2xHP5oZXPlRQPhUDZrbb4PbI3ZJnh66c63eL4ZR8EJ+HRFI0Alx5p69Zw== + +"@swc/core-linux-x64-musl@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.0.tgz#0868518771004753acb07d9871cf5b143b51dc30" + integrity sha512-cEJ2ebtV1v/5Ilb55E05J6F5SrHKQWzUttIhR5Mkayyo+yvPslcpByuFC3D+J7X1ebziTOBpWuMpUdjLfh3SMQ== + +"@swc/core-win32-arm64-msvc@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.0.tgz#43048d67f871e798566c3883c991bed521ef3b9e" + integrity sha512-ecQOOmzEssz+m0pR4xDYCGuvn3E/l0nQ3tk5jp1NA1lsAy4bMV0YbYCHjptYvWL/UjhIerIp3IlCJ8x5DodSog== + +"@swc/core-win32-ia32-msvc@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.0.tgz#6e98f413e6469cfd00dcc7c106cb69f2c709e581" + integrity sha512-gz81seZkRn3zMnVOc7L5k6F4vQC82gIxmHiL+GedK+A37XI/X26AASU3zxvORnqQbwQYXQ+AEVckxBmFlz3v2g== + +"@swc/core-win32-x64-msvc@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.0.tgz#79dfce878552f0a066a40c9cef524f4a8f872674" + integrity sha512-b5Fd1xEOw9uqBpj2lqsaR4Iq9UhiL84hNDcEsi6DQA7Y1l85waQAslTbS0E4/pJ1PISAs0jW0zIGLco1eaWBOg== "@swc/core@^1.5.7": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.6.7.tgz#5d113df161fd8ec29ab8837f385240f41315735e" - integrity sha512-BBzORL9qWz5hZqAZ83yn+WNaD54RH5eludjqIOboolFOK/Pw+2l00/H77H4CEBJnzCIBQszsyqtITmrn4evp0g== + version "1.7.0" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.0.tgz#81f4e7dadf03e1d7f9a5e48a87f5d857e8fc1468" + integrity sha512-d4vMzH6ICllDwlPuhset2h8gu/USHdbyfJim+2hQEdxC0UONtfpmu38XBgNqRjStrji1Q5M10jfeUZL3cu1i8g== dependencies: "@swc/counter" "^0.1.3" "@swc/types" "^0.1.9" optionalDependencies: - "@swc/core-darwin-arm64" "1.6.7" - "@swc/core-darwin-x64" "1.6.7" - "@swc/core-linux-arm-gnueabihf" "1.6.7" - "@swc/core-linux-arm64-gnu" "1.6.7" - "@swc/core-linux-arm64-musl" "1.6.7" - "@swc/core-linux-x64-gnu" "1.6.7" - "@swc/core-linux-x64-musl" "1.6.7" - "@swc/core-win32-arm64-msvc" "1.6.7" - "@swc/core-win32-ia32-msvc" "1.6.7" - "@swc/core-win32-x64-msvc" "1.6.7" + "@swc/core-darwin-arm64" "1.7.0" + "@swc/core-darwin-x64" "1.7.0" + "@swc/core-linux-arm-gnueabihf" "1.7.0" + "@swc/core-linux-arm64-gnu" "1.7.0" + "@swc/core-linux-arm64-musl" "1.7.0" + "@swc/core-linux-x64-gnu" "1.7.0" + "@swc/core-linux-x64-musl" "1.7.0" + "@swc/core-win32-arm64-msvc" "1.7.0" + "@swc/core-win32-ia32-msvc" "1.7.0" + "@swc/core-win32-x64-msvc" "1.7.0" "@swc/counter@^0.1.3": version "0.1.3" @@ -906,9 +921,9 @@ integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== "@swc/types@^0.1.9": - version "0.1.9" - resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.9.tgz#e67cdcc2e4dd74a3cef4474b465eb398e7ae83e2" - integrity sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg== + version "0.1.12" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.12.tgz#7f632c06ab4092ce0ebd046ed77ff7557442282f" + integrity sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA== dependencies: "@swc/counter" "^0.1.3" @@ -932,7 +947,7 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== -"@types/prop-types@*", "@types/prop-types@^15.7.11": +"@types/prop-types@*", "@types/prop-types@^15.7.12": version "15.7.12" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== @@ -986,61 +1001,61 @@ csstype "^3.0.2" "@typescript-eslint/eslint-plugin@^7.2.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz#8eaf396ac2992d2b8f874b68eb3fcd6b179cb7f3" - integrity sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA== + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.1.tgz#f5f5da52db674b1f2cdb9d5f3644e5b2ec750465" + integrity sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.15.0" - "@typescript-eslint/type-utils" "7.15.0" - "@typescript-eslint/utils" "7.15.0" - "@typescript-eslint/visitor-keys" "7.15.0" + "@typescript-eslint/scope-manager" "7.16.1" + "@typescript-eslint/type-utils" "7.16.1" + "@typescript-eslint/utils" "7.16.1" + "@typescript-eslint/visitor-keys" "7.16.1" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" ts-api-utils "^1.3.0" "@typescript-eslint/parser@^7.2.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.15.0.tgz#f4a536e5fc6a1c05c82c4d263a2bfad2da235c80" - integrity sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A== - dependencies: - "@typescript-eslint/scope-manager" "7.15.0" - "@typescript-eslint/types" "7.15.0" - "@typescript-eslint/typescript-estree" "7.15.0" - "@typescript-eslint/visitor-keys" "7.15.0" + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.16.1.tgz#84c581cf86c8b2becd48d33ddc41a6303d57b274" + integrity sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA== + dependencies: + "@typescript-eslint/scope-manager" "7.16.1" + "@typescript-eslint/types" "7.16.1" + "@typescript-eslint/typescript-estree" "7.16.1" + "@typescript-eslint/visitor-keys" "7.16.1" debug "^4.3.4" -"@typescript-eslint/scope-manager@7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz#201b34b0720be8b1447df17b963941bf044999b2" - integrity sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw== +"@typescript-eslint/scope-manager@7.16.1": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz#2b43041caabf8ddd74512b8b550b9fc53ca3afa1" + integrity sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw== dependencies: - "@typescript-eslint/types" "7.15.0" - "@typescript-eslint/visitor-keys" "7.15.0" + "@typescript-eslint/types" "7.16.1" + "@typescript-eslint/visitor-keys" "7.16.1" -"@typescript-eslint/type-utils@7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz#5b83c904c6de91802fb399305a50a56d10472c39" - integrity sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg== +"@typescript-eslint/type-utils@7.16.1": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.16.1.tgz#4d7ae4f3d9e3c8cbdabae91609b1a431de6aa6ca" + integrity sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA== dependencies: - "@typescript-eslint/typescript-estree" "7.15.0" - "@typescript-eslint/utils" "7.15.0" + "@typescript-eslint/typescript-estree" "7.16.1" + "@typescript-eslint/utils" "7.16.1" debug "^4.3.4" ts-api-utils "^1.3.0" -"@typescript-eslint/types@7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.15.0.tgz#fb894373a6e3882cbb37671ffddce44f934f62fc" - integrity sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw== +"@typescript-eslint/types@7.16.1": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.16.1.tgz#bbab066276d18e398bc64067b23f1ce84dfc6d8c" + integrity sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ== -"@typescript-eslint/typescript-estree@7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz#e323bfa3966e1485b638ce751f219fc1f31eba37" - integrity sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ== +"@typescript-eslint/typescript-estree@7.16.1": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.1.tgz#9b145ba4fd1dde1986697e1ce57dc501a1736dd3" + integrity sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ== dependencies: - "@typescript-eslint/types" "7.15.0" - "@typescript-eslint/visitor-keys" "7.15.0" + "@typescript-eslint/types" "7.16.1" + "@typescript-eslint/visitor-keys" "7.16.1" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -1048,22 +1063,22 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.15.0.tgz#9e6253c4599b6e7da2fb64ba3f549c73eb8c1960" - integrity sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA== +"@typescript-eslint/utils@7.16.1": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.16.1.tgz#df42dc8ca5a4603016fd102db0346cdab415cdb7" + integrity sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "7.15.0" - "@typescript-eslint/types" "7.15.0" - "@typescript-eslint/typescript-estree" "7.15.0" + "@typescript-eslint/scope-manager" "7.16.1" + "@typescript-eslint/types" "7.16.1" + "@typescript-eslint/typescript-estree" "7.16.1" -"@typescript-eslint/visitor-keys@7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz#1da0726201a859343fe6a05742a7c1792fff5b66" - integrity sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw== +"@typescript-eslint/visitor-keys@7.16.1": + version "7.16.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz#4287bcf44c34df811ff3bb4d269be6cfc7d8c74b" + integrity sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg== dependencies: - "@typescript-eslint/types" "7.15.0" + "@typescript-eslint/types" "7.16.1" eslint-visitor-keys "^3.4.3" "@ungap/structured-clone@^1.2.0": @@ -1123,9 +1138,9 @@ ansi-styles@^4.1.0: color-convert "^2.0.1" apexcharts@^3.50.0: - version "3.50.0" - resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.50.0.tgz#9030f206183978df0d762602b3d15b59ec6e783b" - integrity sha512-LJT1PNAm+NoIU3aogL2P+ViC0y/Cjik54FdzzGV54UNnGQLBoLe5ok3fxsJDTgyez45BGYT8gqNpYKqhdfy5sg== + version "3.51.0" + resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.51.0.tgz#f99d8a7f49045b61bab795522f35233faac5fe94" + integrity sha512-WpCdVdGiJjf9SAyEeg2rl3q5OqCcNqiEmH0+filMraUiH6Vqyn5GFeMMyH0pon44xjNr1G0xzIRERKRmsGEuRA== dependencies: "@yr/monotone-cubic-spline" "^1.0.3" svg.draggable.js "^2.2.2" @@ -1181,15 +1196,15 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browserslist@^4.22.2: - version "4.23.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.1.tgz#ce4af0534b3d37db5c1a4ca98b9080f985041e96" - integrity sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw== +browserslist@^4.23.1: + version "4.23.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed" + integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA== dependencies: - caniuse-lite "^1.0.30001629" - electron-to-chromium "^1.4.796" + caniuse-lite "^1.0.30001640" + electron-to-chromium "^1.4.820" node-releases "^2.0.14" - update-browserslist-db "^1.0.16" + update-browserslist-db "^1.1.0" callsites@^3.0.0: version "3.1.0" @@ -1201,10 +1216,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001629: - version "1.0.30001640" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz#32c467d4bf1f1a0faa63fc793c2ba81169e7652f" - integrity sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA== +caniuse-lite@^1.0.30001640: + version "1.0.30001643" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz#9c004caef315de9452ab970c3da71085f8241dbd" + integrity sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg== chalk@^2.4.2: version "2.4.2" @@ -1233,7 +1248,7 @@ clsx@^1.1.0: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== -clsx@^2.1.0: +clsx@^2.1.0, clsx@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== @@ -1312,6 +1327,11 @@ csstype@^3.0.2, csstype@^3.1.3: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +dayjs@^1.11.12: + version "1.11.12" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.12.tgz#5245226cc7f40a15bf52e0b99fd2a04669ccac1d" + integrity sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg== + debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.5" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" @@ -1354,10 +1374,10 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -electron-to-chromium@^1.4.796: - version "1.4.818" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.818.tgz#7762c8bfd15a07c3833b7f5deed990e9e5a4c24f" - integrity sha512-eGvIk2V0dGImV9gWLq8fDfTTsCAeMDwZqEPMr+jMInxZdnp9Us8UpovYpRCf9NQ7VOFgrN2doNSgvISbsbNpxA== +electron-to-chromium@^1.4.820: + version "1.4.832" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.832.tgz#d25882ce0a9237577b039bffa124ecef1822003b" + integrity sha512-cTen3SB0H2SGU7x467NRe1eVcQgcuS6jckKfWJHia2eo0cHIGOqHoAxevIYZD4eRHcWjkvFzo93bi3vJ9W+1lA== entities@^4.4.0: version "4.5.0" @@ -1421,9 +1441,9 @@ eslint-plugin-react-hooks@^4.6.0: integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== eslint-plugin-react-refresh@^0.4.6: - version "0.4.7" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.7.tgz#1f597f9093b254f10ee0961c139a749acb19af7d" - integrity sha512-yrj+KInFmwuQS2UQcg1SF83ha1tuHC1jMQbRNyuWtlEzzKRDgAl7L4Yp4NlDUZTZNlWvHEzOtJhMi40R7JxcSw== + version "0.4.9" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.9.tgz#bf870372b353b12e1e6fb7fc41b282d9cbc8d93d" + integrity sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA== eslint-scope@^7.2.2: version "7.2.2" @@ -1492,9 +1512,9 @@ espree@^9.6.0, espree@^9.6.1: eslint-visitor-keys "^3.4.1" esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -1735,9 +1755,9 @@ is-arrayish@^0.2.1: integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-core-module@^2.13.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" - integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== dependencies: hasown "^2.0.2" @@ -1929,9 +1949,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + version "2.0.17" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.17.tgz#d74bc4fec38d839eec5db2a3c9c963d4f33cb366" + integrity sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA== notistack@^3.0.1: version "3.0.1" @@ -2084,18 +2104,18 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^18.2.0: +react-is@^18.3.1: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== react-router-dom@^6.23.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.24.1.tgz#b1a22f7d6c5a1bfce30732bd370713f991ab4de4" - integrity sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg== + version "6.25.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.25.1.tgz#b89f8d63fc8383ea4e89c44bf31c5843e1f7afa0" + integrity sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ== dependencies: - "@remix-run/router" "1.17.1" - react-router "6.24.1" + "@remix-run/router" "1.18.0" + react-router "6.25.1" react-router-hash-link@^2.4.3: version "2.4.3" @@ -2104,12 +2124,12 @@ react-router-hash-link@^2.4.3: dependencies: prop-types "^15.7.2" -react-router@6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.24.1.tgz#5a3bbba0000afba68d42915456ca4c806f37a7de" - integrity sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg== +react-router@6.25.1: + version "6.25.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.25.1.tgz#70b4f1af79954cfcfd23f6ddf5c883e8c904203e" + integrity sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw== dependencies: - "@remix-run/router" "1.17.1" + "@remix-run/router" "1.18.0" react-tooltip@^5.27.0: version "5.27.1" @@ -2168,28 +2188,28 @@ rimraf@^3.0.2: glob "^7.1.3" rollup@^4.13.0: - version "4.18.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.18.0.tgz#497f60f0c5308e4602cf41136339fbf87d5f5dda" - integrity sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg== + version "4.19.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.19.0.tgz#83b08cc0b2bc38c26c194cb7f2cdabd84a2a8c02" + integrity sha512-5r7EYSQIowHsK4eTZ0Y81qpZuJz+MUuYeqmmYmRMl1nwhdmbiYqt5jwzf6u7wyOzJgYqtCRMtVRKOtHANBz7rA== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.18.0" - "@rollup/rollup-android-arm64" "4.18.0" - "@rollup/rollup-darwin-arm64" "4.18.0" - "@rollup/rollup-darwin-x64" "4.18.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.18.0" - "@rollup/rollup-linux-arm-musleabihf" "4.18.0" - "@rollup/rollup-linux-arm64-gnu" "4.18.0" - "@rollup/rollup-linux-arm64-musl" "4.18.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.18.0" - "@rollup/rollup-linux-riscv64-gnu" "4.18.0" - "@rollup/rollup-linux-s390x-gnu" "4.18.0" - "@rollup/rollup-linux-x64-gnu" "4.18.0" - "@rollup/rollup-linux-x64-musl" "4.18.0" - "@rollup/rollup-win32-arm64-msvc" "4.18.0" - "@rollup/rollup-win32-ia32-msvc" "4.18.0" - "@rollup/rollup-win32-x64-msvc" "4.18.0" + "@rollup/rollup-android-arm-eabi" "4.19.0" + "@rollup/rollup-android-arm64" "4.19.0" + "@rollup/rollup-darwin-arm64" "4.19.0" + "@rollup/rollup-darwin-x64" "4.19.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.19.0" + "@rollup/rollup-linux-arm-musleabihf" "4.19.0" + "@rollup/rollup-linux-arm64-gnu" "4.19.0" + "@rollup/rollup-linux-arm64-musl" "4.19.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.19.0" + "@rollup/rollup-linux-riscv64-gnu" "4.19.0" + "@rollup/rollup-linux-s390x-gnu" "4.19.0" + "@rollup/rollup-linux-x64-gnu" "4.19.0" + "@rollup/rollup-linux-x64-musl" "4.19.0" + "@rollup/rollup-win32-arm64-msvc" "4.19.0" + "@rollup/rollup-win32-ia32-msvc" "4.19.0" + "@rollup/rollup-win32-x64-msvc" "4.19.0" fsevents "~2.3.2" run-parallel@^1.1.9: @@ -2212,9 +2232,9 @@ semver@^6.3.1: integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== semver@^7.6.0: - version "7.6.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== shebang-command@^2.0.0: version "2.0.0" @@ -2391,7 +2411,7 @@ typescript@^5.2.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== -update-browserslist-db@^1.0.16: +update-browserslist-db@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== @@ -2416,9 +2436,9 @@ vite-plugin-svgr@^4.2.0: "@svgr/plugin-jsx" "^8.1.0" vite@^5.2.0: - version "5.3.3" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.3.tgz#5265b1f0a825b3b6564c2d07524777c83e3c04c2" - integrity sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A== + version "5.3.4" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.4.tgz#b36ebd47c8a5e3a8727046375d5f10bf9fdf8715" + integrity sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA== dependencies: esbuild "^0.21.3" postcss "^8.4.39" From c5df5afd657c69b3114b3300eed2d6abae2ddd92 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Wed, 24 Jul 2024 17:44:44 +0200 Subject: [PATCH 12/22] vinvoor: support empty response bodies --- vingo/handlers/cards.go | 4 ++-- vingo/handlers/settings.go | 2 +- vinvoor/src/util/fetch.ts | 22 +++++++++++++--------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/vingo/handlers/cards.go b/vingo/handlers/cards.go index accd969..1d4bd1d 100644 --- a/vingo/handlers/cards.go +++ b/vingo/handlers/cards.go @@ -26,7 +26,7 @@ func (Cards) StartRegister(c *fiber.Ctx) error { logger.Println("Card registration started by user", registering_user) - return c.Status(200).JSON(map[string]bool{}) + return c.SendStatus(200) } func (Cards) Get(c *fiber.Ctx) error { @@ -68,5 +68,5 @@ func (Cards) Update(c *fiber.Ctx) error { return c.Status(500).SendString("Error updating card name") } - return c.Status(200).JSON(map[string]bool{}) + return c.SendStatus(200) } diff --git a/vingo/handlers/settings.go b/vingo/handlers/settings.go index 5627c05..9cccef5 100644 --- a/vingo/handlers/settings.go +++ b/vingo/handlers/settings.go @@ -29,7 +29,7 @@ func (Settings) Update(c *fiber.Ctx) error { sess.Set(STORE_USER, &user) sess.Save() - return c.Status(200).JSON(map[string]bool{}) + return c.SendStatus(200) } func (Settings) Get(c *fiber.Ctx) error { diff --git a/vinvoor/src/util/fetch.ts b/vinvoor/src/util/fetch.ts index 3f45a84..c7a8c7c 100644 --- a/vinvoor/src/util/fetch.ts +++ b/vinvoor/src/util/fetch.ts @@ -46,15 +46,19 @@ const _fetch = async ( ): Promise => { return fetch(url, { credentials: "include", ...options }) .then((response) => { - if (!response.ok) { - const error = new Error( - "Fetch failed with status: " + response.status - ) as ResponseNot200Error; - error.response = response; - throw error; - } - - return response.json(); + const contentType = response.headers.get("content-type"); + + if (contentType && contentType.includes("application/json")) { + if (!response.ok) { + const error = new Error( + "Fetch failed with status: " + response.status + ) as ResponseNot200Error; + error.response = response; + throw error; + } + + return response.json(); + } else return response; }) .then((data) => (convertData ? convertData(data) : data)); }; From 758ea794a346064993b37b7469602725aaacbdfc Mon Sep 17 00:00:00 2001 From: Topvennie Date: Wed, 24 Jul 2024 18:08:05 +0200 Subject: [PATCH 13/22] vingo: return status codes for admin routes --- vingo/handlers/days.go | 4 ++-- vinvoor/src/providers/UserProvider.tsx | 2 +- vinvoor/src/util/fetch.ts | 22 +++++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/vingo/handlers/days.go b/vingo/handlers/days.go index 8dd0e6e..25dcdb6 100644 --- a/vingo/handlers/days.go +++ b/vingo/handlers/days.go @@ -27,7 +27,7 @@ func (Days) CreateMultiple(c *fiber.Ctx) error { return c.Status(500).SendString("Error creating days") } - return c.Redirect("/days") + return c.SendStatus(200) } func (Days) Delete(c *fiber.Ctx) error { @@ -38,5 +38,5 @@ func (Days) Delete(c *fiber.Ctx) error { return c.Status(500).SendString("Error deleting day") } - return c.Redirect("/days") + return c.SendStatus(200) } diff --git a/vinvoor/src/providers/UserProvider.tsx b/vinvoor/src/providers/UserProvider.tsx index f145e97..eb778d3 100644 --- a/vinvoor/src/providers/UserProvider.tsx +++ b/vinvoor/src/providers/UserProvider.tsx @@ -62,8 +62,8 @@ export const UserProvider: FC = ({ children }) => { newUserState.error = error; }) .finally(() => { - newUserState.loading = false; setUserState(newUserState); + newUserState.loading = false; }); }, []); diff --git a/vinvoor/src/util/fetch.ts b/vinvoor/src/util/fetch.ts index c7a8c7c..a16ef1e 100644 --- a/vinvoor/src/util/fetch.ts +++ b/vinvoor/src/util/fetch.ts @@ -46,19 +46,19 @@ const _fetch = async ( ): Promise => { return fetch(url, { credentials: "include", ...options }) .then((response) => { - const contentType = response.headers.get("content-type"); + if (!response.ok) { + const error = new Error( + "Fetch failed with status: " + response.status + ) as ResponseNot200Error; + error.response = response; + throw error; + } - if (contentType && contentType.includes("application/json")) { - if (!response.ok) { - const error = new Error( - "Fetch failed with status: " + response.status - ) as ResponseNot200Error; - error.response = response; - throw error; - } + const contentType = response.headers.get("content-type"); - return response.json(); - } else return response; + return contentType && contentType.includes("application/json") + ? response.json() + : response.text(); }) .then((data) => (convertData ? convertData(data) : data)); }; From 8400e88170af9fa004908cbde1afe5d33a104908 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Sun, 28 Jul 2024 16:04:42 +0200 Subject: [PATCH 14/22] vinvoor: minor adjustments --- vinvoor/.gitignore | 2 ++ vinvoor/src/overview/days/Days.tsx | 2 +- vinvoor/src/theme.ts | 8 +------- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/vinvoor/.gitignore b/vinvoor/.gitignore index 3bb6b40..fc04cb3 100644 --- a/vinvoor/.gitignore +++ b/vinvoor/.gitignore @@ -27,3 +27,5 @@ dist-ssr bin/ pkg/ .env + +test.js diff --git a/vinvoor/src/overview/days/Days.tsx b/vinvoor/src/overview/days/Days.tsx index eb032d6..fb97935 100644 --- a/vinvoor/src/overview/days/Days.tsx +++ b/vinvoor/src/overview/days/Days.tsx @@ -10,7 +10,7 @@ const getDayCount = (scans: readonly Scan[]) => { scans.forEach((scan) => { days[scan.scanTime.getDay() - 1]++; }); - return days.slice(0, -2); + return days.slice(0, -2) as ApexNonAxisChartSeries; }; export const Days = () => { diff --git a/vinvoor/src/theme.ts b/vinvoor/src/theme.ts index 82b12e2..ff1bb50 100644 --- a/vinvoor/src/theme.ts +++ b/vinvoor/src/theme.ts @@ -80,6 +80,7 @@ export const hiddenTheme = createTheme({ }, background: { default: "#FED8B1", + paper: "#ECB176", }, success: { main: "#355E3B", @@ -115,13 +116,6 @@ export const hiddenTheme = createTheme({ color4: "#381b06", }, components: { - MuiPaper: { - styleOverrides: { - root: { - backgroundColor: "#ECB176", - }, - }, - }, MuiDivider: { styleOverrides: { root: { From 8e6a721a1cb2b8845e3d4b394412b9dde1f7923b Mon Sep 17 00:00:00 2001 From: Vincent Vallaeys Date: Tue, 30 Jul 2024 00:18:06 +0200 Subject: [PATCH 15/22] vinvoor: improve heatmap (#40) * vinvoor: start new heatmap * vinvoor: improve heatmap --- vinvoor/src/components/BrowserView.tsx | 16 +- vinvoor/src/navbar/NavBarLogo.tsx | 2 +- vinvoor/src/overview/Overview.tsx | 83 ++--- vinvoor/src/overview/heatmap/Day.tsx | 195 ++++++++++++ vinvoor/src/overview/heatmap/Heatmap.tsx | 309 +++---------------- vinvoor/src/overview/heatmap/LabelsMonth.tsx | 102 ++++++ vinvoor/src/overview/heatmap/Rect.tsx | 36 +++ vinvoor/src/overview/heatmap/heatmap.css | 9 +- vinvoor/src/overview/heatmap/types.ts | 31 ++ vinvoor/src/overview/heatmap/utils.ts | 175 +++++------ vinvoor/src/theme.ts | 2 +- 11 files changed, 542 insertions(+), 418 deletions(-) create mode 100644 vinvoor/src/overview/heatmap/Day.tsx create mode 100644 vinvoor/src/overview/heatmap/LabelsMonth.tsx create mode 100644 vinvoor/src/overview/heatmap/Rect.tsx create mode 100644 vinvoor/src/overview/heatmap/types.ts diff --git a/vinvoor/src/components/BrowserView.tsx b/vinvoor/src/components/BrowserView.tsx index 1f05829..bdee5ac 100644 --- a/vinvoor/src/components/BrowserView.tsx +++ b/vinvoor/src/components/BrowserView.tsx @@ -1,13 +1,25 @@ import { useMediaQuery, useTheme } from "@mui/material"; -import { FC } from "react"; +import { FC, useEffect } from "react"; interface BrowserViewProps { + onMobileView?: () => void; + onBrowserView?: () => void; children: React.ReactNode; } -export const BrowserView: FC = ({ children }) => { +export const BrowserView: FC = ({ + onMobileView, + onBrowserView, + children, +}) => { const theme = useTheme(); const isMobileView = useMediaQuery(theme.breakpoints.down("md")); + // Only run callbacks after the component has rendered + useEffect(() => { + if (isMobileView) onMobileView?.(); + else onBrowserView?.(); + }, [isMobileView]); + return isMobileView ? null : <>{children}; }; diff --git a/vinvoor/src/navbar/NavBarLogo.tsx b/vinvoor/src/navbar/NavBarLogo.tsx index a89a57e..12c86b3 100644 --- a/vinvoor/src/navbar/NavBarLogo.tsx +++ b/vinvoor/src/navbar/NavBarLogo.tsx @@ -9,7 +9,7 @@ interface NavBarLogoProps { } const CLICK_AMOUNT = 10; -const CLICK_TIME_MS = 900; +const CLICK_TIME_MS = 1000; let pressedAmount = 0; let startTimePress = 0; diff --git a/vinvoor/src/overview/Overview.tsx b/vinvoor/src/overview/Overview.tsx index 61377c6..0e90f30 100644 --- a/vinvoor/src/overview/Overview.tsx +++ b/vinvoor/src/overview/Overview.tsx @@ -1,6 +1,6 @@ import { Box, Paper, Stack, Switch, Typography } from "@mui/material"; import Grid from "@mui/material/Grid"; -import { createContext, useEffect, useRef, useState } from "react"; +import { createContext, useLayoutEffect, useRef, useState } from "react"; import { Tooltip } from "react-tooltip"; import { BrowserView } from "../components/BrowserView"; import { LoadingSkeleton } from "../components/LoadingSkeleton"; @@ -8,7 +8,8 @@ import { useFetch } from "../hooks/useFetch"; import { convertScanJSON, Scan } from "../types/scans"; import { CheckIn } from "./checkin/CheckIn"; import { Days } from "./days/Days"; -import { Heatmap, HeatmapVariant } from "./heatmap/Heatmap"; +import { Heatmap } from "./heatmap/Heatmap"; +import { HeatmapVariant } from "./heatmap/types"; import { Streak } from "./streak/Streak"; interface ScanContextProps { @@ -28,22 +29,15 @@ export const Overview = () => { ); const [checked, setChecked] = useState(false); const daysRef = useRef(null); - const heatmapSwitchRef = useRef(null); - const [heatmapSwitchHeight, setHeatmapSwitchHeight] = useState(0); const [paperHeight, setPaperHeight] = useState(0); const handleChange = (event: React.ChangeEvent) => { setChecked(event.target.checked); }; - useEffect(() => { - if (daysRef.current) { - setPaperHeight(daysRef.current.clientHeight); - } - - if (heatmapSwitchRef.current) { - setHeatmapSwitchHeight(heatmapSwitchRef.current.clientHeight); - } + useLayoutEffect(() => { + if (daysRef.current) + setPaperHeight(daysRef.current.getBoundingClientRect().height); }); return ( @@ -61,40 +55,47 @@ export const Overview = () => { - - + setChecked(false)} > - Months - - Days - - - - + + Months + + Days + + + + + diff --git a/vinvoor/src/overview/heatmap/Day.tsx b/vinvoor/src/overview/heatmap/Day.tsx new file mode 100644 index 0000000..4f0a3a5 --- /dev/null +++ b/vinvoor/src/overview/heatmap/Day.tsx @@ -0,0 +1,195 @@ +import { useTheme } from "@mui/material"; +import { FC, useContext, useMemo } from "react"; +import { ScanContext } from "../Overview"; +import "./heatmap.css"; +import { Rect } from "./Rect"; +import { DayData, HeatmapVariant } from "./types"; +import { + DATE_FORMATTER, + DAYS_IN_WEEK, + formatData, + getColumnCountMonths, + getMondayIndexedDay, + isDayVariant, + MILLISECONDS_IN_DAY, + styleMonth, + WEEKS_IN_MONTH, +} from "./utils"; + +interface DayProps { + startDate: Date; + endDate: Date; + columnCount: number; + transform: string; + isSmallView: boolean; + variant: HeatmapVariant; +} + +export const Day: FC = ({ + startDate, + endDate, + columnCount, + transform, + isSmallView, + variant, +}) => { + const theme = useTheme(); + const { scans } = useContext(ScanContext); + + const data = useMemo(() => { + const normalizedScans = [...scans]; + normalizedScans.forEach((scan) => scan.scanTime.setHours(0, 0, 0, 0)); + const formattedScans = formatData(normalizedScans); + + const start = new Date( + startDate.getTime() - + startDate.getDay() * MILLISECONDS_IN_DAY + + MILLISECONDS_IN_DAY + ); + + const startDates = [ + ...Array(getColumnCountMonths(startDate, endDate)), + ].map((_, idx) => { + const newStartDate = new Date(startDate); + if (idx === 0) { + while (newStartDate.getDay() !== 1) { + newStartDate.setDate(newStartDate.getDate() - 1); + } + } else { + newStartDate.setMonth(newStartDate.getMonth() + idx); + newStartDate.setDate(1); + while (newStartDate.getDay() !== 1) { + newStartDate.setDate(newStartDate.getDate() + 1); + } + } + + return newStartDate; + }); + + const endWeek = new Date( + endDate.getTime() + + MILLISECONDS_IN_DAY * + (DAYS_IN_WEEK - + (getMondayIndexedDay(endDate) % DAYS_IN_WEEK)) + ); + + return { + data: formattedScans, + start, + endWeek, + startDates, + }; + }, [scans, startDate, endDate]); + + return ( + + {[...Array(columnCount)].map((_, idx) => { + return ( + + {isDayVariant(variant) + ? [...Array(DAYS_IN_WEEK)].map((_, cidx) => { + const currentDate = new Date( + data.start.getTime() + + MILLISECONDS_IN_DAY * + (idx * DAYS_IN_WEEK + cidx) + ); + + if ( + currentDate.getTime() < + startDate.getTime() + ) + return null; + + if (currentDate.getTime() > endDate.getTime()) + return null; + + let colors = theme.heatmap.colorInActive; + if (data.data[currentDate.getTime()]) + colors = theme.heatmap.colorActive; + + const dataTooltipContent = `${ + data.data[currentDate.getTime()] + ? "Present" + : "Absent" + } on ${DATE_FORMATTER.format(currentDate)}`; + + return ( + + ); + }) + : [...Array(WEEKS_IN_MONTH)].map((_, cidx) => { + const currentDate = new Date( + data.startDates[idx].getTime() + + MILLISECONDS_IN_DAY * + cidx * + DAYS_IN_WEEK + ); + + // Week is no longer in the month + if ( + currentDate.getMonth() > + startDate.getMonth() + idx && + getMondayIndexedDay(currentDate) <= + currentDate.getDate() - 1 + ) + return null; + + // Week is after end date + if ( + currentDate.getTime() >= + data.endWeek.getTime() + ) + return null; + + const count = [...Array(DAYS_IN_WEEK)] + .map( + (_, i) => + new Date( + currentDate.getTime() + + i * MILLISECONDS_IN_DAY + ) + ) + .filter( + (date) => + date.getTime() <= + endDate.getTime() && + data.data[date.getTime()] + ).length; + + const colors = + styleMonth[Math.min(count, 5)](theme); // Can be higher than 5 if multiple scans in a day or scanned during the weekend + + const dataTooltipContent = `${count} scan${ + count !== 1 ? "s" : "" + } in the week of ${DATE_FORMATTER.format( + currentDate + )}`; + + return ( + + ); + })} + + ); + })} + + ); +}; diff --git a/vinvoor/src/overview/heatmap/Heatmap.tsx b/vinvoor/src/overview/heatmap/Heatmap.tsx index e09ce90..f5f3c1d 100644 --- a/vinvoor/src/overview/heatmap/Heatmap.tsx +++ b/vinvoor/src/overview/heatmap/Heatmap.tsx @@ -1,282 +1,65 @@ -import { Box } from "@mui/material"; -import { Theme, useTheme } from "@mui/material/styles"; -import { FC, useContext } from "react"; -import { MILLISECONDS_IN_ONE_DAY, shiftDate } from "../../util/util"; -import { ScanContext } from "../Overview"; -import "./heatmap.css"; +import { useMediaQuery, useTheme } from "@mui/material"; +import { FC } from "react"; +import { Day } from "./Day"; +import { LabelsMonth } from "./LabelsMonth"; +import { HeatmapVariant } from "./types"; import { - dateTimeFormat, DAYS_IN_WEEK, - getColumnCount, - getEmpty, - getHeight, - getMonthLabelCoordinates, - getSquareCoordinates, - getTransformForAllWeeks, - getTransformForColumn, - getTransformForMonthLabels, - getWidth, - MONTH_LABELS, - SQUARE_SIZE, - styleMonth, + getColumnCountDays, + getColumnCountMonths, + isDayVariant, + LEFT_PAD, + RECT_SIZE, + SPACE, + TOP_PAD, + WEEKS_IN_MONTH, } from "./utils"; -export interface HeatmapItem { - date: Date; - count: number; -} - -export enum HeatmapVariant { - DAYS, - MONTHS, -} - interface HeatmapProps { startDate: Date; endDate: Date; variant: HeatmapVariant; - maxHeight: number; } -const getAllValues = ( - days: readonly Date[], - startDate: Date, - endDate: Date, - variant: HeatmapVariant -): HeatmapItem[] => { - const values: readonly HeatmapItem[] = days.map((date) => ({ - date, - count: 1, - })); - if (variant === HeatmapVariant.DAYS) { - return Array.from( - { - length: - (endDate.getTime() - startDate.getTime()) / - MILLISECONDS_IN_ONE_DAY + - 1, - }, - (_, i) => { - const date = shiftDate(startDate, i); - return ( - values.find((v) => v.date.getTime() === date.getTime()) || { - date, - count: 0, - } - ); - } - ); - } else { - return Array.from( - { - length: getColumnCount(startDate, endDate, HeatmapVariant.DAYS), - }, - (_, i) => { - const start = shiftDate(startDate, i * DAYS_IN_WEEK); - const count = Array.from({ - length: DAYS_IN_WEEK, - }).reduce((sum, _, j) => { - const date = shiftDate(start, j); - const value = values.find( - (v) => v.date.getTime() === date.getTime() - ); - return sum + (value ? value.count : 0); - }, 0); - - return { date: start, count }; - } - ); - } -}; - -const getWeeksInMonth = ( - values: HeatmapItem[], - startDate: Date -): Record => { - const startYear = values[0].date.getFullYear(); - return values.reduce( - (acc, value) => { - const index = - (value.date.getFullYear() - startYear) * 12 + - value.date.getMonth() - - startDate.getMonth(); - acc[index] = (acc[index] || 0) + 1; - return acc; - }, - { - [startDate.getMonth()]: getEmpty( - values[0].date, - HeatmapVariant.MONTHS - ), - } as { - [key: number]: number; - } - ); -}; - -const getRectStyling = ( - theme: Theme, - value: HeatmapItem, - variant: HeatmapVariant -) => { - if (variant === HeatmapVariant.DAYS) - if (value.count > 0) return theme.heatmap.colorActive; - else return theme.heatmap.colorInActive; - else return styleMonth[Math.min(value.count, 5)](theme); -}; - -const getTextStyling = (theme: Theme, variant: HeatmapVariant) => { - return { - fill: theme.palette.primary.contrastText, - fontSize: variant === HeatmapVariant.DAYS ? "1.8rem" : "0.8rem", - }; -}; - -const getTooltipDataAttrsForDate = ( - value: HeatmapItem, - variant: HeatmapVariant -) => ({ - "data-tooltip-id": "heatmap", - "data-tooltip-content": - variant === HeatmapVariant.DAYS - ? getTooltipDataAttrsForDays(value) - : getTooltipDataAttrsForMonths(value), -}); - -const getTooltipDataAttrsForDays = (value: HeatmapItem) => - `${value.count > 0 ? "Present" : "Absent"} on ${dateTimeFormat.format( - value.date - )}`; - -const getTooltipDataAttrsForMonths = (value: HeatmapItem) => - `${value.count} scan${ - value.count !== 1 ? "s" : "" - } in the week of ${dateTimeFormat.format(value.date)}`; - -export const Heatmap: FC = ({ - startDate, - endDate, - variant, - maxHeight, -}) => { +export const Heatmap: FC = ({ startDate, endDate, variant }) => { const theme = useTheme(); - const { scans } = useContext(ScanContext); - - const days = scans.map((scan) => scan.scanTime); + const isSmallView = useMediaQuery(theme.breakpoints.down("lg")); - days.forEach((date) => date.setHours(0, 0, 0, 0)); startDate.setHours(0, 0, 0, 0); endDate.setHours(0, 0, 0, 0); - const values = getAllValues(days, startDate, endDate, variant); - - const viewBox = `0 0 ${getWidth(startDate, endDate, variant)} ${getHeight( - variant - )}`; - - const weeksInMonth = - variant === HeatmapVariant.MONTHS - ? getWeeksInMonth(values, startDate) - : {}; // Amount of weeks in each month - - const columns = getColumnCount(startDate, endDate, variant); // Amount of columns of squares - const emptyStart = getEmpty(startDate, variant); // Amount of empty squares at the start - const emptyEnd = getEmpty(endDate, variant); // Amount of empty squares at the end - - let valueIndex = 0; - const renderSquare = (row: number, column: number) => { - if (column === 0 && row < emptyStart) return null; - - if (variant === HeatmapVariant.DAYS) - if (column === columns - 1 && row > emptyEnd) return null; - - const value = values[valueIndex++]; - - const [x, y] = getSquareCoordinates(row); - - return ( - - ); - }; - - const renderColumn = (column: number) => ( - - {[ - ...Array( - variant === HeatmapVariant.DAYS - ? DAYS_IN_WEEK - : weeksInMonth[column] - ).keys(), - ].map((row) => renderSquare(row, column))} - - ); - - const renderColumns = () => - [...Array(columns).keys()].map((column) => renderColumn(column)); - - const renderMonthLabels = () => { - if (variant === HeatmapVariant.DAYS) { - return [...Array(columns).keys()].map((column) => { - const endOfWeek = shiftDate(startDate, column * DAYS_IN_WEEK); - const [x, y] = getMonthLabelCoordinates(variant, column); - - return endOfWeek.getDate() >= 1 && - endOfWeek.getDate() <= DAYS_IN_WEEK ? ( - - {MONTH_LABELS[endOfWeek.getMonth()]} - - ) : null; - }); - } else { - return [...Array(columns).keys()].map((column) => { - if (column % 2 === 1) { - return null; - } - - const [x, y] = getMonthLabelCoordinates(variant, column); - - return ( - - {MONTH_LABELS[startDate.getMonth() + column]} - - ); - }); - } - }; + const columnCount = isDayVariant(variant) + ? getColumnCountDays(startDate, endDate) + : getColumnCountMonths(startDate, endDate); return ( - - - - {renderMonthLabels()} - - - {renderColumns()} - - - + + + + ); }; diff --git a/vinvoor/src/overview/heatmap/LabelsMonth.tsx b/vinvoor/src/overview/heatmap/LabelsMonth.tsx new file mode 100644 index 0000000..6beb9c7 --- /dev/null +++ b/vinvoor/src/overview/heatmap/LabelsMonth.tsx @@ -0,0 +1,102 @@ +import { useTheme } from "@mui/material/styles"; +import { FC, useMemo } from "react"; +import { DayLabel, HeatmapVariant, LabelData, MonthLabel } from "./types"; +import { + DAYS_IN_WEEK, + FONT_SIZE, + getColumnCountDays, + getColumnCountMonths, + isDayVariant, + LEFT_PAD, + MILLISECONDS_IN_DAY, + MONTH_LABELS, + MONTH_RECT_Y, + RECT_SIZE, + SPACE, +} from "./utils"; + +interface LablesMonthProps { + startDate: Date; + endDate: Date; + isSmallView: boolean; + variant: HeatmapVariant; +} + +export const LabelsMonth: FC = ({ + startDate, + endDate, + isSmallView, + variant, +}) => { + const theme = useTheme(); + + const data = useMemo(() => { + const day = [ + ...Array(getColumnCountDays(startDate, endDate) * DAYS_IN_WEEK), + ] + .map((_, idx) => { + if ((idx / DAYS_IN_WEEK) % 1 === 0) { + const date = new Date( + startDate.getTime() + idx * MILLISECONDS_IN_DAY + ); + const month = date.getMonth(); + + return { + col: idx / 7, + month, + monthStr: MONTH_LABELS[month], + }; + } + return {} as DayLabel; + }) + .filter((item) => Object.keys(item).length) + .filter((item, idx, list) => + list[idx - 1] ? list[idx - 1]!.month !== item!.month : true + ); + + const month = [...Array(getColumnCountMonths(startDate, endDate))] + .map((_, idx) => { + const date = new Date(startDate); + date.setMonth(date.getMonth() + idx); + + return { monthStr: MONTH_LABELS[date.getMonth()] }; + }) + .filter((_, idx) => idx % 2 === 0); + return { + day, + month, + }; + }, [startDate, endDate]); + + return ( + <> + {(isDayVariant(variant) + ? (data.day as DayLabel[]) + : (data.month as MonthLabel[]) + ).map((item, idx) => { + return ( + + {item.monthStr} + + ); + })} + + ); +}; diff --git a/vinvoor/src/overview/heatmap/Rect.tsx b/vinvoor/src/overview/heatmap/Rect.tsx new file mode 100644 index 0000000..550f025 --- /dev/null +++ b/vinvoor/src/overview/heatmap/Rect.tsx @@ -0,0 +1,36 @@ +import { FC } from "react"; +import { HeatmapRectStyle } from "../../theme"; +import { RECT_RADIUS, RECT_SIZE, RECT_STROKE, SPACE } from "./utils"; + +interface RectProps { + idx: number; + cidx: number; + isSmallView: boolean; + colors: HeatmapRectStyle; + dataTooltipContent: string; +} + +export const Rect: FC = ({ + idx, + cidx, + isSmallView, + colors, + dataTooltipContent, +}) => { + return ( + + ); +}; diff --git a/vinvoor/src/overview/heatmap/heatmap.css b/vinvoor/src/overview/heatmap/heatmap.css index 6bb2a2f..d4f8cad 100644 --- a/vinvoor/src/overview/heatmap/heatmap.css +++ b/vinvoor/src/overview/heatmap/heatmap.css @@ -1,7 +1,3 @@ -.heatmap rect:hover { - stroke-opacity: 0; -} - @keyframes createBox { from { width: 0; @@ -12,7 +8,6 @@ } } -.rect { - /* animation: createBox 1s; */ - stroke-width: 1px; +.rect:hover { + stroke-opacity: 0; } diff --git a/vinvoor/src/overview/heatmap/types.ts b/vinvoor/src/overview/heatmap/types.ts new file mode 100644 index 0000000..3f933bc --- /dev/null +++ b/vinvoor/src/overview/heatmap/types.ts @@ -0,0 +1,31 @@ +export enum HeatmapVariant { + DAYS, + MONTHS, +} + +export interface HeatmapValue { + date: Date; + count: number; // Could be used in the future for check in and out +} + +export interface DayData { + data: Record; // Each scan + start: Date; // Start brought back to the beginning of the week + endWeek: Date; // First day of the week after the end date + startDates: Record; // Start of each week for each month +} + +export interface DayLabel { + col: number; + month: number; + monthStr: string; +} + +export interface MonthLabel { + monthStr: string; +} + +export interface LabelData { + day: DayLabel[]; + month: MonthLabel[]; +} diff --git a/vinvoor/src/overview/heatmap/utils.ts b/vinvoor/src/overview/heatmap/utils.ts index b427295..94443b9 100644 --- a/vinvoor/src/overview/heatmap/utils.ts +++ b/vinvoor/src/overview/heatmap/utils.ts @@ -1,14 +1,71 @@ -// Exports +import { Theme } from "@mui/material"; +import { Scan } from "../../types/scans"; +import { HeatmapValue, HeatmapVariant } from "./types"; + +export const getColumnCountDays = (startDate: Date, endDate: Date) => { + const startOfWeek = new Date(startDate); + startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay()); + + const endOfWeek = new Date(endDate); + if (endOfWeek.getDay() === 0) + endOfWeek.setDate(endOfWeek.getDate() - endOfWeek.getDay()); + else endOfWeek.setDate(endOfWeek.getDate() - endOfWeek.getDay() + 6); + + return Math.ceil( + (endOfWeek.getTime() - startOfWeek.getTime()) / + (DAYS_IN_WEEK * MILLISECONDS_IN_DAY) + ); +}; + +export const getColumnCountMonths = (startDate: Date, endDate: Date) => { + return ( + (endDate.getFullYear() - startDate.getFullYear()) * 12 + + endDate.getMonth() - + startDate.getMonth() + + 1 + ); +}; + +export const getMondayIndexedDay = (date: Date) => (date.getDay() + 6) % 7; + +export const formatData = (scans: Scan[]) => { + const result: Record = {}; + scans.forEach((scan) => { + result[scan.scanTime.getTime()] = { + date: scan.scanTime, + count: 1, + }; + }); + + return result; +}; -import { Theme } from "@mui/material/styles"; -import { MILLISECONDS_IN_ONE_DAY } from "../../util/util"; -import { HeatmapVariant } from "./Heatmap"; +export const isDayVariant = (variant: HeatmapVariant) => + variant === HeatmapVariant.DAYS; + +export const styleMonth = [ + (theme: Theme) => theme.heatmap.color0, + (theme: Theme) => theme.heatmap.color1, + (theme: Theme) => theme.heatmap.color2, + (theme: Theme) => theme.heatmap.color3, + (theme: Theme) => theme.heatmap.color4, + (theme: Theme) => theme.heatmap.color5, +]; // Constants -export const DAYS_IN_WEEK = 7; -export const WEEKS_IN_MONTH = 5; -export const SQUARE_SIZE = 10; +// Size + +export const RECT_SIZE = (isSmallView: boolean) => (isSmallView ? 5 : 20); +export const RECT_RADIUS = (isSmallView: boolean) => (isSmallView ? 1 : 4); +export const RECT_STROKE = (isSmallView: boolean) => (isSmallView ? 1 : 2); +export const SPACE = (isSmallView: boolean) => (isSmallView ? 2 : 10); +export const TOP_PAD = (isSmallView: boolean) => (isSmallView ? 8 : 25); +export const LEFT_PAD = (isSmallView: boolean) => (isSmallView ? 2 : 5); +export const MONTH_RECT_Y = (isSmallView: boolean) => (isSmallView ? 5 : 15); +export const FONT_SIZE = (isSmallView: boolean) => (isSmallView ? 4 : 15); + +// Month labels export const MONTH_LABELS = [ "Jan", @@ -24,105 +81,17 @@ export const MONTH_LABELS = [ "Nov", "Dec", ]; -export const dateTimeFormat = new Intl.DateTimeFormat("en-GB", { + +// Formatter + +export const DATE_FORMATTER = new Intl.DateTimeFormat("en-GB", { year: "2-digit", month: "short", day: "numeric", }); -// Labels - -export const getMonthLabelSize = (variant: HeatmapVariant) => - SQUARE_SIZE + - MONTH_LABEL_GUTTER_SIZE(variant) + - MONTH_LABEL_OFFSET(variant); - -export const getMonthLabelCoordinates = ( - variant: HeatmapVariant, - column: number -) => [ - column * getSquareSize(), - getMonthLabelSize(variant) - MONTH_LABEL_GUTTER_SIZE(variant), -]; - -// Transforms - -export const getTransformForColumn = (column: number) => - `translate(${column * getSquareSize() + GUTTERSIZE}, 0)`; +// Consts -export const getTransformForAllWeeks = (variant: HeatmapVariant) => - `translate(0, ${getMonthLabelSize(variant)})`; - -export const getTransformForMonthLabels = () => `translate(0, 0)`; - -export const getWidth = ( - startDate: Date, - endDate: Date, - variant: HeatmapVariant -) => getColumnCount(startDate, endDate, variant) * getSquareSize() + GUTTERSIZE; - -export const getHeight = (variant: HeatmapVariant) => { - if (variant === HeatmapVariant.DAYS) - return DAYS_IN_WEEK * getSquareSize() + getMonthLabelSize(variant); - else return WEEKS_IN_MONTH * getSquareSize() + getMonthLabelSize(variant); -}; - -// Coordinate - -export const getSquareCoordinates = (dayIndex: number) => [ - 0, - dayIndex * getSquareSize(), -]; - -// Utils - -export const getEmpty = (date: Date, variant: HeatmapVariant) => { - if (variant === HeatmapVariant.DAYS) - return (date.getDay() + DAYS_IN_WEEK - 1) % DAYS_IN_WEEK; - else return Math.floor((date.getDate() - 1) / DAYS_IN_WEEK); -}; - -export const getColumnCount = ( - startDate: Date, - endDate: Date, - variant: HeatmapVariant -) => { - if (variant === HeatmapVariant.DAYS) { - const startOfWeek = new Date(startDate); - startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay()); - - const endOfWeek = new Date(endDate); - if (endOfWeek.getDay() === 0) - endOfWeek.setDate(endOfWeek.getDate() - endOfWeek.getDay()); - else endOfWeek.setDate(endOfWeek.getDate() - endOfWeek.getDay() + 6); - - return Math.ceil( - (endOfWeek.getTime() - startOfWeek.getTime()) / - (DAYS_IN_WEEK * MILLISECONDS_IN_ONE_DAY) - ); - } else { - return ( - (endDate.getFullYear() - startDate.getFullYear()) * 12 + - (endDate.getMonth() - startDate.getMonth() + 1) - ); - } -}; - -export const styleMonth = [ - (theme: Theme) => theme.heatmap.color0, - (theme: Theme) => theme.heatmap.color1, - (theme: Theme) => theme.heatmap.color2, - (theme: Theme) => theme.heatmap.color3, - (theme: Theme) => theme.heatmap.color4, - (theme: Theme) => theme.heatmap.color5, -]; - -// Local functions - -const GUTTERSIZE = 5; -const MONTH_LABEL_GUTTER_SIZE = (variant: HeatmapVariant) => - variant === HeatmapVariant.DAYS ? 15 : 8; -const MONTH_LABEL_OFFSET = (variant: HeatmapVariant) => - variant === HeatmapVariant.DAYS ? 15 : 0; - -const getSquareSize = () => SQUARE_SIZE + GUTTERSIZE; +export const DAYS_IN_WEEK = 7; +export const WEEKS_IN_MONTH = 5; +export const MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; diff --git a/vinvoor/src/theme.ts b/vinvoor/src/theme.ts index ff1bb50..457fc5e 100644 --- a/vinvoor/src/theme.ts +++ b/vinvoor/src/theme.ts @@ -163,7 +163,7 @@ export const hiddenTheme = createTheme({ }, }); -interface HeatmapRectStyle { +export interface HeatmapRectStyle { fill: string; stroke: string; } From 7ecab8d72636248b1754dcaf109506c70190c0b6 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Mon, 5 Aug 2024 21:56:58 +0200 Subject: [PATCH 16/22] vinvoor: remove heatmap border --- vinvoor/src/overview/heatmap/Heatmap.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/vinvoor/src/overview/heatmap/Heatmap.tsx b/vinvoor/src/overview/heatmap/Heatmap.tsx index f5f3c1d..4066bfd 100644 --- a/vinvoor/src/overview/heatmap/Heatmap.tsx +++ b/vinvoor/src/overview/heatmap/Heatmap.tsx @@ -34,7 +34,6 @@ export const Heatmap: FC = ({ startDate, endDate, variant }) => { return ( Date: Mon, 5 Aug 2024 22:12:01 +0200 Subject: [PATCH 17/22] vingo: fix days endpoint --- vingo/database/days.go | 53 ++++++++++++++++++------------------------ vingo/handlers/days.go | 10 ++++++++ vingo/main.go | 1 + 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/vingo/database/days.go b/vingo/database/days.go index c2b5e02..73daecc 100644 --- a/vingo/database/days.go +++ b/vingo/database/days.go @@ -1,28 +1,28 @@ package database -import "time" +import ( + "time" -func CreateDays(first_day time.Time, last_day time.Time) error { - tx, err := db.Begin() - if err != nil { - return err - } + "gorm.io/gorm" +) - defer tx.Rollback() - - for d := first_day; !d.After(last_day); d = d.AddDate(0, 0, 1) { - // Ignore weekends - if d.Weekday() == time.Saturday || d.Weekday() == time.Sunday { - continue +func CreateDays(first_day time.Time, last_day time.Time) error { + err := gorm_db.Transaction(func(tx *gorm.DB) error { + for d := first_day; !d.After(last_day); d = d.AddDate(0, 0, 1) { + // Ignore weekends + if d.Weekday() == time.Saturday || d.Weekday() == time.Sunday { + continue + } + + if err := tx.Create(&StreakDay{Date: d}).Error; err != nil { + return err + } } - _, err := db.Exec("INSERT INTO days (date) VALUES ($1);", d) - if err != nil { - return err - } - } + return nil + }) - if err = tx.Commit(); err != nil { + if err != nil { return err } @@ -30,23 +30,14 @@ func CreateDays(first_day time.Time, last_day time.Time) error { } func GetDays() ([]StreakDay, error) { - rows, err := db.Query("SELECT id, date FROM days ORDER BY date;") - if err != nil { - return nil, err - } - - days := make([]StreakDay, 0) - for rows.Next() { - var day StreakDay - rows.Scan(&day.Id, &day.Date) - days = append(days, day) - } + var days []StreakDay + err := gorm_db.Find(&days).Error - return days, nil + return days, err } func DeleteDay(dayId string) error { - _, err := db.Exec("DELETE FROM days WHERE id = $1;", dayId) + _, err := db.Exec("DELETE FROM streak_days WHERE id = $1;", dayId) if err != nil { return err } diff --git a/vingo/handlers/days.go b/vingo/handlers/days.go index 25dcdb6..d0b8a8b 100644 --- a/vingo/handlers/days.go +++ b/vingo/handlers/days.go @@ -40,3 +40,13 @@ func (Days) Delete(c *fiber.Ctx) error { return c.SendStatus(200) } + +func (Days) All(c *fiber.Ctx) error { + days, err := database.GetDays() + if err != nil { + logger.Println("Error getting days:", err) + return c.Status(500).SendString("Error getting days") + } + + return c.JSON(days) +} diff --git a/vingo/main.go b/vingo/main.go index d56e6de..8a6405c 100644 --- a/vingo/main.go +++ b/vingo/main.go @@ -56,6 +56,7 @@ func main() { admin := api.Group("/admin", handlers.IsAdmin) { + admin.Get("/days", handlers.Days{}.All) admin.Post("/days", handlers.Days{}.CreateMultiple) admin.Delete("/days/:id", handlers.Days{}.Delete) } From 1662dbdbdf5d877f39cf635fd04fcf7357a41d0c Mon Sep 17 00:00:00 2001 From: Topvennie Date: Tue, 6 Aug 2024 21:39:40 +0200 Subject: [PATCH 18/22] vinvoor: admin day selector --- vingo/database/models.go | 2 +- vingo/handlers/days.go | 4 +- vinvoor/src/components/LoadingSkeleton.tsx | 6 +- vinvoor/src/overview/checkin/CheckIn.tsx | 4 +- vinvoor/src/scans/Scans.tsx | 2 +- .../{ScansBody.tsx => ScansTableBody.tsx} | 0 vinvoor/src/settings/admin/Admin.tsx | 97 +++-------- vinvoor/src/settings/admin/days/Days.tsx | 63 +++++++ vinvoor/src/settings/admin/days/DaysAdd.tsx | 88 ++++++++++ vinvoor/src/settings/admin/days/DaysTable.tsx | 160 ++++++++++++++++++ .../src/settings/admin/days/DaysTableBody.tsx | 84 +++++++++ .../src/settings/admin/days/DaysTableHead.tsx | 63 +++++++ .../settings/admin/days/DaysTableToolbar.tsx | 126 ++++++++++++++ vinvoor/src/types/days.ts | 28 +++ vinvoor/src/util/fetch.ts | 35 ++-- 15 files changed, 658 insertions(+), 104 deletions(-) rename vinvoor/src/scans/{ScansBody.tsx => ScansTableBody.tsx} (100%) create mode 100644 vinvoor/src/settings/admin/days/Days.tsx create mode 100644 vinvoor/src/settings/admin/days/DaysAdd.tsx create mode 100644 vinvoor/src/settings/admin/days/DaysTable.tsx create mode 100644 vinvoor/src/settings/admin/days/DaysTableBody.tsx create mode 100644 vinvoor/src/settings/admin/days/DaysTableHead.tsx create mode 100644 vinvoor/src/settings/admin/days/DaysTableToolbar.tsx create mode 100644 vinvoor/src/types/days.ts diff --git a/vingo/database/models.go b/vingo/database/models.go index f5d8085..7c49878 100644 --- a/vingo/database/models.go +++ b/vingo/database/models.go @@ -77,5 +77,5 @@ type Season struct { type StreakDay struct { BaseModel - Date time.Time + Date time.Time `json:"date"` } diff --git a/vingo/handlers/days.go b/vingo/handlers/days.go index d0b8a8b..2b0eba8 100644 --- a/vingo/handlers/days.go +++ b/vingo/handlers/days.go @@ -10,8 +10,8 @@ import ( type Days struct{} type DaysBody struct { - StartDate time.Time `json:"start_date"` - EndDate time.Time `json:"end_date"` + StartDate time.Time `json:"startDate"` + EndDate time.Time `json:"endDate"` } func (Days) CreateMultiple(c *fiber.Ctx) error { diff --git a/vinvoor/src/components/LoadingSkeleton.tsx b/vinvoor/src/components/LoadingSkeleton.tsx index 04ff32e..4c20e9a 100644 --- a/vinvoor/src/components/LoadingSkeleton.tsx +++ b/vinvoor/src/components/LoadingSkeleton.tsx @@ -11,9 +11,5 @@ export const LoadingSkeleton: FC = ({ children, ...props }) => { - return loading ? ( - - ) : ( - children - ); + return loading ? : children; }; diff --git a/vinvoor/src/overview/checkin/CheckIn.tsx b/vinvoor/src/overview/checkin/CheckIn.tsx index 667ca64..2cf451d 100644 --- a/vinvoor/src/overview/checkin/CheckIn.tsx +++ b/vinvoor/src/overview/checkin/CheckIn.tsx @@ -21,7 +21,7 @@ export const CheckIn = () => { }} > Checked in - Nice of you to stop by! + Nice of you to stop by ! ) : ( { }} > Not checked in - We miss you! + We miss you ! ); }; diff --git a/vinvoor/src/scans/Scans.tsx b/vinvoor/src/scans/Scans.tsx index ced950f..f4f95a5 100644 --- a/vinvoor/src/scans/Scans.tsx +++ b/vinvoor/src/scans/Scans.tsx @@ -4,7 +4,7 @@ import { LoadingSkeleton } from "../components/LoadingSkeleton"; import { useFetch } from "../hooks/useFetch"; import { Card, convertCardJSON } from "../types/cards"; import { convertScanJSON, Scan } from "../types/scans"; -import { ScansTableBody } from "./ScansBody"; +import { ScansTableBody } from "./ScansTableBody"; import { ScansTableHead } from "./ScansTableHead"; export const Scans = () => { diff --git a/vinvoor/src/scans/ScansBody.tsx b/vinvoor/src/scans/ScansTableBody.tsx similarity index 100% rename from vinvoor/src/scans/ScansBody.tsx rename to vinvoor/src/scans/ScansTableBody.tsx diff --git a/vinvoor/src/settings/admin/Admin.tsx b/vinvoor/src/settings/admin/Admin.tsx index f909c7c..4fb06ba 100644 --- a/vinvoor/src/settings/admin/Admin.tsx +++ b/vinvoor/src/settings/admin/Admin.tsx @@ -1,89 +1,30 @@ -import { Box, Button, Grid, Paper, Stack, Typography } from "@mui/material"; -import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; -import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; -import dayjs, { Dayjs } from "dayjs"; -import { useSnackbar } from "notistack"; -import { Dispatch, FC, SetStateAction, useState } from "react"; -import { postApi } from "../../util/fetch"; +import { Alert, Grid, Typography } from "@mui/material"; +import { FC } from "react"; +import { Days } from "./days/Days"; export const Admin: FC = () => { - const [startDate, setStartDate] = useState(dayjs()); - const [endDate, setEndDate] = useState(dayjs()); - - const { enqueueSnackbar } = useSnackbar(); - - const handleDateChange = ( - date: Dayjs | null, - setter: Dispatch> - ) => setter(date); - - const handleOnClick = () => { - if (!startDate || !endDate) { - enqueueSnackbar("Please select a start and end date", { - variant: "error", - }); - return; - } - - postApi("admin/days", { - start_date: startDate.toISOString(), - end_date: endDate.toISOString(), - }) - .then(() => - enqueueSnackbar("successfully saved days", { - variant: "success", - }) - ) - .catch((error) => - // This is the admin page so just show the error - enqueueSnackbar(`Failed to save days: ${error}`, { - variant: "error", - }) - ); - }; - return ( - - - - Set days - - - - handleDateChange(newValue, setStartDate) - } - /> - - handleDateChange(newValue, setEndDate) - } - /> - - - - - - - + + + + This page doesn't ask for confirmation when modifying + data ! + + + + + ); diff --git a/vinvoor/src/settings/admin/days/Days.tsx b/vinvoor/src/settings/admin/days/Days.tsx new file mode 100644 index 0000000..e88e586 --- /dev/null +++ b/vinvoor/src/settings/admin/days/Days.tsx @@ -0,0 +1,63 @@ +import { Grid } from "@mui/material"; +import { useSnackbar } from "notistack"; +import { createContext, Dispatch, SetStateAction, useState } from "react"; +import { LoadingSkeleton } from "../../../components/LoadingSkeleton"; +import { useFetch } from "../../../hooks/useFetch"; +import { convertDayJSON, Day } from "../../../types/days"; +import { getApi } from "../../../util/fetch"; +import { DaysAdd } from "./DaysAdd"; +import { DaysTable } from "./DaysTable"; + +interface DayContextProps { + days: readonly Day[]; + setDays: Dispatch>; + reloadDays: () => void; +} + +export const DayContext = createContext({ + days: [], + setDays: () => {}, + reloadDays: () => null, +}); + +export const Days = () => { + const [days, setDays] = useState([]); + const { loading } = useFetch( + "admin/days", + setDays, + convertDayJSON + ); + + const { enqueueSnackbar } = useSnackbar(); + + const reloadDays = () => { + getApi("admin/days", convertDayJSON) + .then((data) => setDays(data)) + // This is the admin page so just show the error + .catch((error) => + enqueueSnackbar(`Error getting all days: ${error}`, { + variant: "error", + }) + ); + }; + + return ( + + + + + + + + + + + + + ); +}; diff --git a/vinvoor/src/settings/admin/days/DaysAdd.tsx b/vinvoor/src/settings/admin/days/DaysAdd.tsx new file mode 100644 index 0000000..ba5dd6b --- /dev/null +++ b/vinvoor/src/settings/admin/days/DaysAdd.tsx @@ -0,0 +1,88 @@ +import { Box, Button, Paper, Stack } from "@mui/material"; +import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import dayjs, { Dayjs } from "dayjs"; +import { useSnackbar } from "notistack"; +import { Dispatch, SetStateAction, useContext, useState } from "react"; +import { TypographyG } from "../../../components/TypographyG"; +import { postApi } from "../../../util/fetch"; +import { DayContext } from "./Days"; +export const DaysAdd = () => { + const { reloadDays } = useContext(DayContext); + const [startDate, setStartDate] = useState(dayjs()); + const [endDate, setEndDate] = useState(dayjs()); + + const { enqueueSnackbar } = useSnackbar(); + + const handleDateChange = ( + date: Dayjs | null, + setter: Dispatch> + ) => setter(date); + + const handleOnClick = () => { + if (!startDate || !endDate) { + enqueueSnackbar("Please select a start and end date", { + variant: "error", + }); + return; + } + + postApi("admin/days", { + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + }) + .then(() => { + enqueueSnackbar("successfully saved days", { + variant: "success", + }); + reloadDays(); + }) + .catch((error) => + // This is the admin page so just show the error + enqueueSnackbar(`Failed to save days: ${error}`, { + variant: "error", + }) + ); + }; + + return ( + + + Add days + + + + handleDateChange(newValue, setStartDate) + } + /> + + handleDateChange(newValue, setEndDate) + } + /> + + + + + + + + ); +}; diff --git a/vinvoor/src/settings/admin/days/DaysTable.tsx b/vinvoor/src/settings/admin/days/DaysTable.tsx new file mode 100644 index 0000000..7fc8dee --- /dev/null +++ b/vinvoor/src/settings/admin/days/DaysTable.tsx @@ -0,0 +1,160 @@ +import { Paper, Stack, Table, TableContainer } from "@mui/material"; +import { useSnackbar } from "notistack"; +import { ChangeEvent, useContext, useEffect, useState } from "react"; +import { TypographyG } from "../../../components/TypographyG"; +import { Day } from "../../../types/days"; +import { deleteAPI } from "../../../util/fetch"; +import { randomInt } from "../../../util/util"; +import { DayContext } from "./Days"; +import { DaysTableBody } from "./DaysTableBody"; +import { DaysTableHead } from "./DaysTableHead"; +import { DaysTableToolbar } from "./DaysTableToolbar"; + +export const DaysTable = () => { + const { days, reloadDays } = useContext(DayContext); + const [rows, setRows] = useState(days); + const [selected, setSelected] = useState([]); + const [deleting, setDeleting] = useState(false); + + const [dateFilter, setDateFilter] = useState< + [Date | undefined, Date | undefined] + >([undefined, undefined]); + const [weekdaysFilter, setWeekdaysFilter] = useState(false); + const [weekendsFilter, setWeekendsFilter] = useState(false); + + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + + const filterDays = (): readonly Day[] => { + let filteredDays = [...days]; + if (dateFilter[0] !== undefined && dateFilter[1] !== undefined) { + filteredDays = filteredDays.filter( + (day) => + day.date.getTime() >= dateFilter[0]!.getTime() && + day.date.getTime() <= dateFilter[1]!.getTime() + ); + } + if (weekdaysFilter) { + filteredDays = filteredDays.filter( + (day) => day.date.getDay() !== 0 && day.date.getDay() !== 6 + ); + } + if (weekendsFilter) { + filteredDays = filteredDays.filter( + (day) => day.date.getDay() === 0 || day.date.getDay() === 6 + ); + } + + return filteredDays; + }; + + const handleDelete = async () => { + setDeleting(true); + const key = randomInt(); + enqueueSnackbar("Deleting...", { + variant: "info", + key: key, + persist: true, + }); + + const promises = selected.map((id) => + deleteAPI(`admin/days/${id}`).catch((error) => + // This is the admin page so just show the error + enqueueSnackbar(`Failed to delete streakday ${id}: ${error}`, { + variant: "error", + }) + ) + ); + + await Promise.all(promises); + + closeSnackbar(key); + enqueueSnackbar( + `Deleted ${selected.length} streakday${ + selected.length > 1 ? "s" : "" + }`, + { + variant: "success", + } + ); + + setSelected([]); + setDeleting(false); + reloadDays(); + }; + + const handleSelect = (id: number) => { + const selectedIndex = selected.indexOf(id); + let newSelected: readonly number[] = []; + + switch (selectedIndex) { + case -1: + newSelected = newSelected.concat(selected, id); + break; + case 0: + newSelected = newSelected.concat(selected.slice(1)); + break; + case selected.length - 1: + newSelected = newSelected.concat(selected.slice(0, -1)); + break; + default: + newSelected = newSelected.concat( + selected.slice(0, selectedIndex), + selected.slice(selectedIndex + 1) + ); + } + + setSelected(newSelected); + }; + const handleSelectAll = (event: ChangeEvent) => { + if (event.target.checked) setSelected(rows.map((day) => day.id)); + else setSelected([]); + }; + const isSelected = (id: number) => selected.indexOf(id) !== -1; + + useEffect( + () => setRows(filterDays()), + [days, dateFilter, weekdaysFilter, weekendsFilter] + ); + + return ( + + + Edit Days + + + +
+ + +
+
+
+ + + ); +}; diff --git a/vinvoor/src/settings/admin/days/DaysTableBody.tsx b/vinvoor/src/settings/admin/days/DaysTableBody.tsx new file mode 100644 index 0000000..94f41ac --- /dev/null +++ b/vinvoor/src/settings/admin/days/DaysTableBody.tsx @@ -0,0 +1,84 @@ +import DeleteIcon from "@mui/icons-material/Delete"; +import { + Checkbox, + IconButton, + TableBody, + TableCell, + TableRow, + Typography, +} from "@mui/material"; +import { useSnackbar } from "notistack"; +import { FC, ReactNode, useContext } from "react"; +import { Day, daysHeadCells } from "../../../types/days"; +import { deleteAPI } from "../../../util/fetch"; +import { DayContext } from "./Days"; + +interface DaysTableBodyProps { + rows: readonly Day[]; + handleSelect: (id: number) => void; + isSelected: (id: number) => boolean; + deleting: boolean; +} + +export const DaysTableBody: FC = ({ + rows, + handleSelect, + isSelected, + deleting, +}) => { + const { days, setDays } = useContext(DayContext); + + const { enqueueSnackbar } = useSnackbar(); + + const handleClick = (id: number) => { + if (isSelected(id)) handleSelect(id); // This will remove it from the selected list + + deleteAPI(`admin/days/${id}`) + .then(() => { + enqueueSnackbar("Deleted streakday", { variant: "success" }); + setDays([...days].filter((day) => day.id !== id)); + }) + .catch((error) => + // This is the admin page so just show the error + enqueueSnackbar(`Failed to delete streakday: ${error}`, { + variant: "error", + }) + ); + }; + + return ( + + {rows.map((day) => ( + + handleSelect(day.id)} + > + + + {daysHeadCells.map((headCell) => ( + + + {headCell.convert + ? headCell.convert(day[headCell.id]) + : (day[headCell.id] as ReactNode)} + + + ))} + + handleClick(day.id)} + > + + + + + ))} + + ); +}; diff --git a/vinvoor/src/settings/admin/days/DaysTableHead.tsx b/vinvoor/src/settings/admin/days/DaysTableHead.tsx new file mode 100644 index 0000000..fbaaef0 --- /dev/null +++ b/vinvoor/src/settings/admin/days/DaysTableHead.tsx @@ -0,0 +1,63 @@ +import { + Box, + Button, + Checkbox, + TableCell, + TableHead, + TableRow, + Typography, +} from "@mui/material"; +import { ChangeEvent, FC } from "react"; +import { daysHeadCells } from "../../../types/days"; + +interface DaysTableHeadProps { + rowCount: number; + numSelected: number; + onSelectAll: (event: ChangeEvent) => void; + handleDelete: () => void; + deleting: boolean; +} + +export const DaysTableHead: FC = ({ + rowCount, + numSelected, + onSelectAll, + handleDelete, + deleting, +}) => { + return ( + + + + 0 && numSelected < rowCount + } + checked={rowCount > 0 && numSelected === rowCount} + onChange={onSelectAll} + /> + + {daysHeadCells.map((headCell) => ( + + {headCell.label} + + ))} + + + + + + + + ); +}; diff --git a/vinvoor/src/settings/admin/days/DaysTableToolbar.tsx b/vinvoor/src/settings/admin/days/DaysTableToolbar.tsx new file mode 100644 index 0000000..5b9c12f --- /dev/null +++ b/vinvoor/src/settings/admin/days/DaysTableToolbar.tsx @@ -0,0 +1,126 @@ +import { Checkbox, Stack, Typography } from "@mui/material"; +import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import dayjs, { Dayjs } from "dayjs"; +import { + ChangeEvent, + Dispatch, + FC, + SetStateAction, + useContext, + useState, +} from "react"; +import { DayContext } from "./Days"; + +interface DaysTableToolbarProps { + dateFilter: [Date | undefined, Date | undefined]; + setDateFilter: Dispatch< + SetStateAction<[Date | undefined, Date | undefined]> + >; + weekdaysFilter: boolean; + setWeekdaysFilter: Dispatch>; + weekendsFilter: boolean; + setWeekendsFilter: Dispatch>; +} + +export const DaysTableToolbar: FC = ({ + dateFilter, + setDateFilter, + weekdaysFilter, + setWeekdaysFilter, + weekendsFilter, + setWeekendsFilter, +}) => { + const { days } = useContext(DayContext); + const [startDate, setStartDate] = useState( + days.length ? dayjs(days[0].date) : dayjs() + ); + const [endDate, setEndDate] = useState( + days.length ? dayjs(days[days.length - 1].date) : dayjs() + ); + + const handleDateChange = ( + date: Dayjs | null, + setter: Dispatch>, + index: number + ) => { + setter(date); + + if (dateFilter[0] !== undefined && dateFilter[1] !== undefined) { + const newDateFilter = [...dateFilter]; + newDateFilter[index] = date?.toDate(); + setDateFilter( + newDateFilter as [Date | undefined, Date | undefined] + ); + } + }; + + const handleClickDate = (event: ChangeEvent) => { + if (event.target.checked) + setDateFilter([startDate?.toDate(), endDate?.toDate()]); + else setDateFilter([undefined, undefined]); + }; + + const handleClickBoolean = ( + event: ChangeEvent, + setter: Dispatch> + ) => setter(event.target.checked); + + return ( + + + + Filter date + + + handleDateChange(newValue, setStartDate, 0) + } + /> + + handleDateChange(newValue, setEndDate, 1) + } + /> + + + + + handleClickBoolean(event, setWeekdaysFilter) + } + /> + Only weekdays + + + + handleClickBoolean(event, setWeekendsFilter) + } + /> + Only weekends + + + ); +}; diff --git a/vinvoor/src/types/days.ts b/vinvoor/src/types/days.ts new file mode 100644 index 0000000..5027310 --- /dev/null +++ b/vinvoor/src/types/days.ts @@ -0,0 +1,28 @@ +import { Base, BaseJSON, TableHeadCell } from "./general"; + +interface DayJSON extends BaseJSON { + date: string; +} + +export interface Day extends Base { + date: Date; +} + +export const convertDayJSON = (daysJSON: DayJSON[]): Day[] => + daysJSON + .map((dayJSON) => ({ + date: new Date(dayJSON.date), + id: dayJSON.id, + createdAt: new Date(dayJSON.createdAt), + })) + .sort((a, b) => a.date.getTime() - b.date.getTime()); + +export const daysHeadCells: readonly TableHeadCell[] = [ + { + id: "date", + label: "Date", + align: "left", + padding: "normal", + convert: (value: Date) => value.toDateString(), + }, +]; diff --git a/vinvoor/src/util/fetch.ts b/vinvoor/src/util/fetch.ts index a16ef1e..74daf4c 100644 --- a/vinvoor/src/util/fetch.ts +++ b/vinvoor/src/util/fetch.ts @@ -3,31 +3,38 @@ const URLS: Record = { API: import.meta.env.VITE_API_URL, }; -export const getApi = (endpoint: string, convertData?: (data: any) => T) => { - return _fetch(`${URLS.API}/${endpoint}`, {}, convertData); -}; +export const getApi = (endpoint: string, convertData?: (data: any) => T) => + _fetch(`${URLS.API}/${endpoint}`, {}, convertData); export const postApi = ( endpoint: string, body: Record = {} -) => { - return _fetch(`${URLS.API}/${endpoint}`, { +) => + _fetch(`${URLS.API}/${endpoint}`, { method: "POST", body: JSON.stringify(body), headers: new Headers({ "content-type": "application/json" }), }); -}; export const patchApi = ( endpoint: string, body: Record = {} -) => { - return _fetch(`${URLS.API}/${endpoint}`, { +) => + _fetch(`${URLS.API}/${endpoint}`, { method: "PATCH", body: JSON.stringify(body), headers: new Headers({ "content-type": "application/json" }), }); -}; + +export const deleteAPI = ( + endpoint: string, + body: Record = {} +) => + _fetch(`${URLS.API}/${endpoint}`, { + method: "DELETE", + body: JSON.stringify(body), + headers: new Headers({ "content-type": "application/json" }), + }); interface ResponseNot200Error extends Error { response: Response; @@ -35,16 +42,15 @@ interface ResponseNot200Error extends Error { export const isResponseNot200Error = ( error: any -): error is ResponseNot200Error => { - return (error as ResponseNot200Error).response !== undefined; -}; +): error is ResponseNot200Error => + (error as ResponseNot200Error).response !== undefined; const _fetch = async ( url: string, options: RequestInit = {}, convertData?: (data: any) => T -): Promise => { - return fetch(url, { credentials: "include", ...options }) +): Promise => + fetch(url, { credentials: "include", ...options }) .then((response) => { if (!response.ok) { const error = new Error( @@ -61,4 +67,3 @@ const _fetch = async ( : response.text(); }) .then((data) => (convertData ? convertData(data) : data)); -}; From 410457028b80479b7b6d59e7fbeccc1fed9192c2 Mon Sep 17 00:00:00 2001 From: Topvennie Date: Tue, 6 Aug 2024 21:44:51 +0200 Subject: [PATCH 19/22] vinvoor: admin panel minor visual improvements --- vinvoor/src/settings/admin/days/DaysAdd.tsx | 4 ++-- vinvoor/src/settings/admin/days/DaysTableToolbar.tsx | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/vinvoor/src/settings/admin/days/DaysAdd.tsx b/vinvoor/src/settings/admin/days/DaysAdd.tsx index ba5dd6b..e536998 100644 --- a/vinvoor/src/settings/admin/days/DaysAdd.tsx +++ b/vinvoor/src/settings/admin/days/DaysAdd.tsx @@ -54,7 +54,7 @@ export const DaysAdd = () => { spacing={4} > Add days - + { display="flex" justifyContent="end" width="100%" - sx={{ pr: 2 }} + sx={{ pr: { xs: 1, md: 2 } }} >