Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into sean/storefront
Browse files Browse the repository at this point in the history
SheepTester authored Nov 11, 2023
2 parents 6f834f7 + 6ed4f3e commit b655868
Showing 25 changed files with 561 additions and 74 deletions.
2 changes: 2 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@ const nextConfig = {
domains: [
'acmucsd.s3-us-west-1.amazonaws.com',
'acmucsd.s3.us-west-1.amazonaws.com',
// This one's for Sumeet Bansal
'acmucsd.s3-us-west-1.amazonaws.com',
'acmucsd-membership-portal.s3.us-west-1.amazonaws.com',
// The dev backend test data uses image URLs outside the allowlist
...(isDevelopment ? ['i.imgur.com', 'i.pinimg.com', 'i.etsystatic.com'] : []),
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@
"@next/env": "^13.2.4",
"@svgr/webpack": "^6.5.1",
"@types/totp-generator": "^0.0.5",
"axios": "^1.1.3",
"axios": "^1.6.0",
"axios-middleware": "^0.3.1",
"cookies-next": "^2.1.1",
"cypress": "^13.2.0",
@@ -66,7 +66,7 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"postcss": "^8.4.30",
"postcss": "^8.4.31",
"prettier": "^2.7.1",
"stylelint": "^15.10.1",
"stylelint-config-sass-guidelines": "^10.0.0",
Binary file modified public/assets/graphics/store/hero-photo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions public/assets/icons/dropdown-arrows.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions public/assets/icons/page-left-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions public/assets/icons/page-right-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 97 additions & 0 deletions src/components/common/Dropdown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import DropdownArrow from '@/public/assets/icons/dropdown-arrows.svg';
import { ReactNode, useEffect, useState } from 'react';
import styles from './style.module.scss';

interface Option {
value: string;
label: string;
}

interface DropdownProps {
name: string;
ariaLabel: string;
options: (Option | '---')[];
value: string;
// Justification for disabling rules: This seems to be a false positive.
// https://stackoverflow.com/q/63767199/
// eslint-disable-next-line no-unused-vars
onChange: (value: string) => void;
}

const Dropdown = ({ name, ariaLabel, options, value, onChange }: DropdownProps) => {
const [open, setOpen] = useState(false);

useEffect(() => {
document.addEventListener('click', event => {
if (event.target instanceof Element && event.target.closest(`.${styles.dropdownWrapper}`)) {
return;
}
setOpen(false);
});
}, [open]);

const optionButtons: ReactNode[] = [];
let dividers = 0;
options.forEach(option => {
if (option === '---') {
optionButtons.push(<hr key={dividers} />);
dividers += 1;
} else {
optionButtons.push(
<button
type="button"
className={styles.option}
onClick={event => {
onChange(option.value);
setOpen(false);
event.stopPropagation();
}}
key={option.value}
>
{option.label}
</button>
);
}
});

return (
// Justification for disabling rules: For accessibility reasons, the
// original <select> should be available for keyboard and screen reader
// users. Only the fancy, inaccessible dropdown should be available for
// mouse/touch users.
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div
className={styles.dropdownWrapper}
onClick={e => {
// Using the keyboard to select an option fires the click event on
// <select>; prevent it from opening the fake dropdown. The <select> has
// pointer-events: none so it shouldn't receive the click event any
// other way.
if (e.target instanceof HTMLElement && e.target.tagName === 'SELECT') {
return;
}
setOpen(true);
}}
>
<select
name={name}
id={name}
value={value}
onChange={e => onChange(e.currentTarget.value)}
aria-label={ariaLabel}
>
{options.map(option =>
option !== '---' ? (
<option value={option.value} key={option.value}>
{option.label}
</option>
) : null
)}
</select>
<DropdownArrow className={styles.arrow} aria-hidden />
<div className={`${styles.contents} ${open ? '' : styles.closed}`}>{optionButtons}</div>
</div>
);
};

export default Dropdown;
68 changes: 68 additions & 0 deletions src/components/common/Dropdown/style.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@use 'src/styles/vars.scss' as vars;

.dropdownWrapper {
align-items: center;
cursor: pointer;
display: flex;
gap: 9px;
grid-area: 1 / 2;
position: relative;

select {
appearance: none;
background: none;
border: 0;
color: inherit;
font: inherit;
font-size: 1.5rem;
font-weight: bold;
pointer-events: none;
width: 100%;

option {
background-color: var(--theme-background);
}
}

.arrow {
flex: none;
}

.contents {
background-color: var(--theme-background);
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
cursor: default;
left: 0;
margin-top: 1rem;
padding: 4px 0;
position: absolute;
right: 0;
top: 100%;
transition: all 0.2s;
z-index: 5;

&.closed {
opacity: 0;
transform: translateY(10px);
visibility: hidden;
}

.option {
background: none;
font: inherit;
padding: 5px 0.75rem;
text-align: left;
width: 100%;

&:hover {
background-color: var(--theme-surface-1);
}
}

hr {
border-top: 1px solid var(--theme-surface-1);
margin: 4px 0;
}
}
}
13 changes: 13 additions & 0 deletions src/components/common/Dropdown/style.module.scss.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export type Styles = {
arrow: string;
closed: string;
contents: string;
dropdownWrapper: string;
option: string;
};

export type ClassNames = keyof Styles;

declare const styles: Styles;

export default styles;
73 changes: 73 additions & 0 deletions src/components/common/PaginationControls/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import LeftArrowIcon from '@/public/assets/icons/page-left-icon.svg';
import RightArrowIcon from '@/public/assets/icons/page-right-icon.svg';
import { useEffect, useState } from 'react';
import style from './style.module.scss';

interface PaginationControlsProps {
page: number;
// eslint-disable-next-line no-unused-vars
onPage: (page: number) => void;
pages: number;
}

const PaginationControls = ({ page, onPage, pages }: PaginationControlsProps) => {
const [value, setValue] = useState(String(page + 1));

useEffect(() => {
setValue(String(page + 1));
}, [page]);

return (
<div className={style.paginationBtns}>
<button
type="button"
className={style.paginationBtn}
onClick={() => onPage(page - 1)}
disabled={page <= 0}
>
<LeftArrowIcon />
</button>
<div className={style.paginationText}>
<input
className={style.pageNumber}
type="text"
inputMode="numeric"
pattern="[0-9]*"
value={value}
onChange={e => {
setValue(e.currentTarget.value);
const page = +e.currentTarget.value - 1;
if (Number.isInteger(page) && page >= 0 && page < pages) {
onPage(page);
}
}}
onBlur={e => {
// Clamp page number between 1 and pages
const inputPage = Math.min(
Math.max(Math.trunc(+e.currentTarget.value - 1), 0),
pages - 1
);
if (Number.isNaN(inputPage)) {
setValue(String(page + 1));
} else {
onPage(inputPage);
setValue(String(inputPage + 1));
}
}}
/>
<span>of</span>
<span className={style.pageNumber}>{pages}</span>
</div>
<button
type="button"
className={style.paginationBtn}
onClick={() => onPage(page + 1)}
disabled={page >= pages - 1}
>
<RightArrowIcon />
</button>
</div>
);
};

export default PaginationControls;
37 changes: 37 additions & 0 deletions src/components/common/PaginationControls/style.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.paginationBtns {
align-items: center;
display: flex;
gap: 20px;
justify-content: center;

.paginationBtn {
background: none;
font-size: 0;
padding: 0;

&:disabled {
cursor: auto;
opacity: 0.5;
}
}

.paginationText {
align-items: center;
display: flex;
font-weight: bold;
gap: 1em;

.pageNumber {
width: 24px;

&:is(input) {
border: 1px solid var(--theme-text-on-background-1);
border-radius: 2px;
color: inherit;
font: inherit;
height: 24px;
text-align: center;
}
}
}
}
12 changes: 12 additions & 0 deletions src/components/common/PaginationControls/style.module.scss.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type Styles = {
pageNumber: string;
paginationBtn: string;
paginationBtns: string;
paginationText: string;
};

export type ClassNames = keyof Styles;

declare const styles: Styles;

export default styles;
2 changes: 2 additions & 0 deletions src/components/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { default as Button } from './Button';
export { default as Dropdown } from './Dropdown';
export { default as PaginationControls } from './PaginationControls';
export { default as SEO } from './SEO';
export { default as VerticalForm } from './VerticalForm';
2 changes: 1 addition & 1 deletion src/components/layout/Navbar/index.tsx
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ const Navbar = ({ user }: NavbarProps) => {
<Link
className={styles.mobileNavItem}
onClick={() => setMenuOpen(false)}
href="/leaderboard"
href={config.leaderboardRoute}
>
<LeaderboardIcon className={styles.iconLink} />
Leaderboard
29 changes: 25 additions & 4 deletions src/components/leaderboard/LeaderboardRow/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isSrcAGif } from '@/lib/utils';
import Image from 'next/image';
import Link from 'next/link';
import type { RefObject } from 'react';
import { useEffect, useRef } from 'react';
import styles from './style.module.scss';

interface LeaderboardRowProps {
@@ -15,7 +15,7 @@ interface LeaderboardRowProps {
index: number;
length: number;
};
rowRef: RefObject<HTMLAnchorElement> | null;
scrollIntoView: number;
}

const LeaderboardRow = ({
@@ -26,10 +26,31 @@ const LeaderboardRow = ({
points,
image,
match,
rowRef,
scrollIntoView,
}: LeaderboardRowProps) => {
const ref = useRef<HTMLAnchorElement>(null);

useEffect(() => {
if (scrollIntoView > 0) {
const row = ref.current;
if (!row) {
return;
}
row.scrollIntoView({ behavior: 'smooth', block: 'center' });
// Remove `.flash` in case it was already applied
row.classList.remove(styles.flash);
const observer = new IntersectionObserver(([entry]) => {
if (entry?.isIntersecting) {
row.classList.add(styles.flash);
observer.disconnect();
}
});
observer.observe(row);
}
}, [scrollIntoView]);

return (
<Link href={url} className={styles.row} ref={rowRef}>
<Link href={url} className={styles.row} ref={ref}>
<span className={styles.position}>{position}</span>
<Image
src={image}
22 changes: 22 additions & 0 deletions src/components/leaderboard/LeaderboardRow/style.module.scss
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
min-height: 4rem;
padding: 0.5rem;
padding-right: 2rem;
transition: none;

@media (max-width: vars.$breakpoint-md) {
gap: 1rem;
@@ -20,6 +21,26 @@
background-color: var(--theme-background);
}

&.flash {
animation: flash 2s;
@keyframes flash {
0%,
20%,
40%,
60% {
background-color: var(--theme-background);
color: var(--theme-text-on-background-1);
}

10%,
30%,
50% {
background-color: var(--theme-primary-2);
color: var(--theme-background);
}
}
}

.position {
font-size: 1.25rem;
font-weight: bold;
@@ -29,6 +50,7 @@

.profilePicture {
border-radius: 50%;
object-fit: cover;
}

.nameRank {
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type Styles = {
flash: string;
match: string;
name: string;
nameRank: string;
2 changes: 1 addition & 1 deletion src/components/leaderboard/TopThreeCard/style.module.scss
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@
flex-direction: column;
height: 100%;
justify-content: space-between;
padding: 16px 32px;
padding: 1rem;
width: 165px;

.cardText {
1 change: 0 additions & 1 deletion src/components/leaderboard/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
/* eslint-disable import/prefer-default-export */
export { default as LeaderboardRow } from './LeaderboardRow';
export { default as TopThreeCard } from './TopThreeCard';
1 change: 1 addition & 0 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -69,6 +69,7 @@ const config = {
},
homeRoute: '/',
loginRoute: '/login',
leaderboardRoute: '/leaderboard',
userProfileRoute: '/u/',
storeRoute: '/store',
cartRoute: '/store/cart',
146 changes: 119 additions & 27 deletions src/pages/leaderboard.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { Dropdown, PaginationControls } from '@/components/common';
import { LeaderboardRow, TopThreeCard } from '@/components/leaderboard';
import { config } from '@/lib';
import { LeaderboardAPI } from '@/lib/api';
import withAccessType from '@/lib/hoc/withAccessType';
import { CookieService, PermissionService } from '@/lib/services';
import { SlidingLeaderboardQueryParams } from '@/lib/types/apiRequests';
import { PrivateProfile, PublicProfile } from '@/lib/types/apiResponses';
import { CookieType } from '@/lib/types/enums';
import { getProfilePicture, getUserRank } from '@/lib/utils';
import MyPositionIcon from '@/public/assets/icons/my-position-icon.svg';
import styles from '@/styles/pages/leaderboard.module.scss';
import { GetServerSideProps } from 'next';
import { useRef, useState } from 'react';
import { useRouter } from 'next/router';
import { useMemo, useState } from 'react';

/** Year ACM was founded. */
const START_YEAR = 2019;
/** Number of seconds in a day. */
const DAY_SECONDS = 86400;

interface Match {
index: number;
@@ -23,18 +31,79 @@ function filter<T extends PublicProfile>(users: T[], query: string): (T & { matc
});
}

function getEndYear(): number {
const today = new Date();
// Arbitrarily start the next academic year in August
return today.getMonth() < 7 ? today.getFullYear() : today.getFullYear() + 1;
}

function getLeaderboardRange(sort: string | number, limit = 0): SlidingLeaderboardQueryParams {
const params: SlidingLeaderboardQueryParams = { limit };
const now = Date.now() / 1000;
switch (sort) {
case 'past-week': {
params.from = now - DAY_SECONDS * 7;
break;
}
case 'past-month': {
params.from = now - DAY_SECONDS * 28;
break;
}
case 'past-year': {
params.from = now - DAY_SECONDS * 365;
break;
}
case 'all-time': {
break;
}
default: {
const year = +sort;
// Arbitrarily academic years on August 1, which should be during the summer
params.from = new Date(year, 7, 1).getTime() / 1000;
params.to = new Date(year + 1, 7, 1).getTime() / 1000;
}
}
return params;
}

const ROWS_PER_PAGE = 100;

interface LeaderboardProps {
sort: string;
leaderboard: PublicProfile[];
user: PrivateProfile;
}

const LeaderboardPage = ({ leaderboard, user: { uuid } }: LeaderboardProps) => {
const LeaderboardPage = ({ sort, leaderboard, user: { uuid } }: LeaderboardProps) => {
const router = useRouter();

const [page, setPage] = useState(0);
const [query, setQuery] = useState('');
const myPosition = useRef<HTMLAnchorElement>(null);
// Using a number to force LeaderboardRow's useEffect to run again when the
// user presses the button multiple times
const [scrollIntoView, setScrollIntoView] = useState(0);

const years = useMemo(() => {
const endYear = getEndYear();
const years = [];
for (let year = START_YEAR; year < endYear; year += 1) {
years.unshift({ value: String(year), label: `${year}${year + 1}` });
}
return years;
}, []);

const results = leaderboard.map((user, index) => ({ ...user, position: index + 1 }));
const topThreeUsers = query === '' ? filter(results.slice(0, 3), query) : [];
const leaderboardRows = filter(query === '' ? results.slice(3) : results, query);
const { allRows, myIndex } = useMemo(() => {
const results = leaderboard.map((user, index) => ({ ...user, position: index + 1 }));
const allRows = filter(results, query);
const myIndex = allRows.findIndex(row => row.uuid === uuid);
return { allRows, myIndex };
}, [leaderboard, query, uuid]);

const topThreeUsers = page === 0 && query === '' ? allRows.slice(0, 3) : [];
const leaderboardRows =
page === 0 && query === ''
? allRows.slice(3, ROWS_PER_PAGE)
: allRows.slice(page * ROWS_PER_PAGE, (page + 1) * ROWS_PER_PAGE);

return (
<div className={styles.container}>
@@ -44,28 +113,44 @@ const LeaderboardPage = ({ leaderboard, user: { uuid } }: LeaderboardProps) => {
className={styles.myPosition}
type="button"
onClick={() => {
myPosition.current?.scrollIntoView();
// Remove `.flash` in case it was already applied
myPosition.current?.classList.remove(styles.flash);
window.requestAnimationFrame(() => {
myPosition.current?.classList.add(styles.flash);
});
setPage(Math.floor(myIndex / ROWS_PER_PAGE));
setScrollIntoView(n => n + 1);
}}
disabled={myIndex === -1}
>
My Position
<MyPositionIcon />
<MyPositionIcon aria-hidden />
</button>
<input
className={styles.search}
type="search"
placeholder="Search Users"
aria-label="Search Users"
value={query}
onChange={e => setQuery(e.currentTarget.value)}
onChange={e => {
setQuery(e.currentTarget.value);
setPage(0);
setScrollIntoView(0);
}}
/>
<Dropdown
name="timeOptions"
ariaLabel="Filter the leaderboard by time"
options={[
{ value: 'past-week', label: 'Past week' },
{ value: 'past-month', label: 'Past month' },
{ value: 'past-year', label: 'Past year' },
{ value: 'all-time', label: 'All time' },
'---',
...years,
]}
value={sort}
onChange={sort => {
router.push(`${config.leaderboardRoute}?sort=${sort}`);
setPage(0);
setScrollIntoView(0);
}}
/>
<select name="timeOptions" id="timeOptions">
<option>All Time</option>
</select>
</div>
{topThreeUsers.length > 0 && (
<div className={styles.topThreeContainer}>
@@ -95,31 +180,38 @@ const LeaderboardPage = ({ leaderboard, user: { uuid } }: LeaderboardProps) => {
points={user.points}
image={getProfilePicture(user)}
match={user.match}
rowRef={user.uuid === uuid ? myPosition : null}
scrollIntoView={user.uuid === uuid ? scrollIntoView : 0}
/>
);
})}
</div>
)}
{topThreeUsers.length === 0 && leaderboardRows.length === 0 && <p>No results.</p>}
{allRows.length > 0 ? (
<PaginationControls
page={page}
onPage={page => {
setPage(page);
setScrollIntoView(0);
}}
pages={Math.ceil(allRows.length / ROWS_PER_PAGE)}
/>
) : (
<p>No results.</p>
)}
</div>
);
};

export default LeaderboardPage;

const getServerSidePropsFunc: GetServerSideProps = async ({ req, res }) => {
const getServerSidePropsFunc: GetServerSideProps = async ({ req, res, query }) => {
const AUTH_TOKEN = CookieService.getServerCookie(CookieType.ACCESS_TOKEN, { req, res });

// Get all leaderboard items
const leaderboard = await LeaderboardAPI.getLeaderboard(AUTH_TOKEN, {
limit: 0,
});
const sort = typeof query.sort === 'string' ? query.sort : getEndYear() - 1;
const leaderboard = await LeaderboardAPI.getLeaderboard(AUTH_TOKEN, getLeaderboardRange(sort));

return {
props: {
leaderboard,
},
props: { sort, leaderboard },
};
};

3 changes: 2 additions & 1 deletion src/styles/globals.scss
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ body {
line-height: 1.5;
margin: 0;
padding: 0;
scroll-padding-top: 4.25rem;
}

main {
@@ -113,5 +114,5 @@ button {

input:-webkit-autofill,
input:-webkit-autofill:focus {
transition: background-color 600000s 0s, color 600000s 0s;
transition: background-color 600000s 0s;
}
25 changes: 5 additions & 20 deletions src/styles/pages/leaderboard.module.scss
Original file line number Diff line number Diff line change
@@ -41,6 +41,11 @@
height: 2rem;
justify-self: start;
padding: 0 1rem;

&:disabled {
cursor: auto;
opacity: 0.5;
}
}

.search {
@@ -83,24 +88,4 @@
margin: 0 -2rem;
}
}

.flash {
animation: flash 2s;
@keyframes flash {
0%,
20%,
40%,
60% {
background-color: var(--theme-background);
color: var(--theme-text-on-background-1);
}

10%,
30%,
50% {
background-color: var(--theme-primary-2);
color: var(--theme-background);
}
}
}
}
1 change: 0 additions & 1 deletion src/styles/pages/leaderboard.module.scss.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export type Styles = {
container: string;
flash: string;
header: string;
heading: string;
leaderboard: string;
64 changes: 48 additions & 16 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -59,6 +59,16 @@
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"

"@babel/generator@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
dependencies:
"@babel/types" "^7.23.0"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"

"@babel/helper-annotate-as-pure@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
@@ -132,6 +142,14 @@
"@babel/template" "^7.22.5"
"@babel/types" "^7.22.5"

"@babel/helper-function-name@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
"@babel/template" "^7.22.15"
"@babel/types" "^7.23.0"

"@babel/helper-hoist-variables@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
@@ -262,6 +280,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==

"@babel/parser@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==

"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.15":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz#02dc8a03f613ed5fdc29fb2f728397c78146c962"
@@ -1002,18 +1025,18 @@
"@babel/types" "^7.22.15"

"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.20.tgz#db572d9cb5c79e02d83e5618b82f6991c07584c9"
integrity sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==
version "7.23.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
dependencies:
"@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.22.15"
"@babel/generator" "^7.23.0"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.22.5"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/parser" "^7.22.16"
"@babel/types" "^7.22.19"
"@babel/parser" "^7.23.0"
"@babel/types" "^7.23.0"
debug "^4.1.0"
globals "^11.1.0"

@@ -1026,6 +1049,15 @@
"@babel/helper-validator-identifier" "^7.22.19"
to-fast-properties "^2.0.0"

"@babel/types@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"

"@colors/colors@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
@@ -1398,7 +1430,7 @@
prop-types "^15.8.1"
react-is "^18.2.0"

"@next/env@13.5.2", "@next/env@^13.2.4":
"@next/env@13.5.2":
version "13.5.2"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.5.2.tgz#1c09e6cf1df8b1edf3cf0ca9c0e0119a49802a5d"
integrity sha512-dUseBIQVax+XtdJPzhwww4GetTjlkRSsXeQnisIJWBaHsnxYcN2RGzsPHi58D6qnkATjnhuAtQTJmR1hKYQQPg==
@@ -2077,10 +2109,10 @@ axios-middleware@^0.3.1:
resolved "https://registry.yarnpkg.com/axios-middleware/-/axios-middleware-0.3.1.tgz#2dd29ee5a821b2499be887e256d60872eb715542"
integrity sha512-DuPLxZgqBYnRgEhEUulNzPspf0j9jlH5iWOJHEfuLFfsxWLc7vjeOxR903dp+G+nrU3TYWbg2COLZ4PDUwh87g==

axios@^1.1.3:
version "1.5.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267"
integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==
axios@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102"
integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
@@ -5139,10 +5171,10 @@ postcss@^6.0.1:
source-map "^0.6.1"
supports-color "^5.4.0"

postcss@^8.3.11, postcss@^8.4.27, postcss@^8.4.30:
version "8.4.30"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7"
integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==
postcss@^8.3.11, postcss@^8.4.27, postcss@^8.4.31:
version "8.4.31"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"

0 comments on commit b655868

Please sign in to comment.