Google auth working

This commit is contained in:
Fergal Moran
2023-02-24 17:50:02 +00:00
parent 15e0f87207
commit 98481f8e55
32 changed files with 753 additions and 751 deletions

View File

@@ -12,39 +12,43 @@
},
"dependencies": {
"@headlessui/react": "^1.7.11",
"@next/font": "13.1.5",
"@next/font": "13.2.0",
"@prisma/client": "^4.9.0",
"@types/node": "18.11.18",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"@types/feather-icons": "^4.29.1",
"@types/node": "18.14.1",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"@upstash/qstash": "^0.3.6",
"classnames": "^2.3.2",
"daisyui": "^2.49.0",
"encoding": "^0.1.13",
"eslint": "8.32.0",
"eslint-config-next": "13.1.5",
"feather-icons": "^4.29.0",
"firebase": "^9.17.1",
"firebase-functions": "^4.2.1",
"fireschema": "^4.0.4",
"next": "13.1.5",
"next": "13.2.0",
"next-logger": "^3.0.1",
"next-seo": "^5.15.0",
"pino": "^8.11.0",
"pino-logflare": "^0.3.12",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-dropzone": "^14.2.3",
"react-feather": "^2.0.10",
"react-hot-toast": "^2.4.0",
"react-icons": "^4.7.1",
"theme-change": "^2.3.0",
"twilio": "^4.8.0",
"typescript": "4.9.4",
"zod": "^3.20.6"
},
"packageManager": "yarn@1.22.19",
"devDependencies": {
"@google-cloud/local-auth": "2.1.0",
"@google-cloud/local-auth": "2.1.1",
"autoprefixer": "^10.4.13",
"googleapis": "105",
"googleapis": "111.0.0",
"postcss": "^8.4.21",
"prettier": "^2.8.3",
"prettier-plugin-tailwindcss": "^0.2.2",

View File

@@ -4,7 +4,7 @@ import React from "react";
const Login = async () => {
return (
<>
<div className="flex flex-wrap justify-evenly w-full">
<div className="flex flex-wrap w-full justify-evenly">
<LoginPage />
</div>
</>);

View File

@@ -1,5 +1,6 @@
"use client";
import React from "react";
import { themeChange } from "theme-change";
import "./globals.css";
import { Inter } from "@next/font/google";
import { NavBar } from "@/components/layout";
@@ -9,26 +10,27 @@ import { Toaster } from "react-hot-toast";
const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({
children
}: {
children,
}: {
children: React.ReactNode;
}) {
React.useEffect(() => {
themeChange(false);
}, []);
return (
<html lang="en" data-theme="bumblebee">
<head />
<body className={`${inter.className} h-screen`}>
<AuthUserProvider>
<div className="min-h-screen w-full bg-base-100 text-base-content m-auto">
<div className="max-w-7xl flex flex-col min-h-screen mx-auto p-5">
<Toaster />
<NavBar />
<main className="flex-1">
{children}
</main>
</div>
</div>
</AuthUserProvider>
</body>
<html lang="en">
<head />
<body>
<AuthUserProvider>
<div className="w-full min-h-screen m-auto bg-base-100 text-base-content">
<div className="flex flex-col min-h-screen p-5 mx-auto max-w-7xl">
<Toaster />
<NavBar />
<main className="flex-1">{children}</main>
</div>
</div>
</AuthUserProvider>
</body>
</html>
);
}

View File

@@ -54,7 +54,7 @@ const Home = async () => {
<div className="leading-5 text-gray-900">{show.title}</div>
</td>
<td className="px-2 py-4">
<RemindMeButton show={show} />
<RemindMeButton showId={show.id} />
</td>
</tr>
))}

View File

@@ -5,7 +5,7 @@ import useFirebaseAuth from "@/lib/auth/useFirebaseAuth";
import { IoLogoFacebook, IoLogoGoogle, IoLogoTwitter } from "react-icons/io";
const LoginPage = () => {
const { signInWithGoogle, signInWithFacebook, signInWithTwitter, user, signIn } =
const { signInWithGoogle, signInWithFacebook, signInWithTwitter, profile, signIn } =
useFirebaseAuth();
const router = useRouter();
const [email, setEmail] = React.useState("");

View File

@@ -12,12 +12,12 @@ import Signup from "@/app/(auth)/signup/page";
const ThemeToggle = dynamic(
() => import("@/components/widgets/ui/theme/ThemeToggle"),
{
ssr: false,
ssr: false
}
);
const Navbar = () => {
const { user, loading, logOut } = useAuthUserContext();
const NavMenu = user ? (
const { profile, loading, logOut } = useAuthUserContext();
const NavMenu = profile ? (
<React.Fragment>
<Link
href="/profile"
@@ -41,7 +41,7 @@ const Navbar = () => {
<Link
href="/signup"
id="signup"
className="font-normal normal-case font-body btn-primary btn-sm btn"
className="font-normal normal-case font-body btn-primary btn-sm btn text-primary-content"
>
<PlusSquare size={12} className="mr-2" />
Register
@@ -56,11 +56,13 @@ const Navbar = () => {
return (
<nav className="w-full mb-2 navbar">
<Link href="/">
<Image src="/logo.png" alt="Otherway" width={32} height={32} />
<Image src="/logo.png" alt="Otherway" width={48} height={48} />
</Link>
<div className="flex-col hidden ml-auto text-sm text-center font-body lg:flex lg:flex-row lg:space-x-10">
<div className="flex-col hidden ml-auto text-sm text-center font-body md:flex md:flex-row md:space-x-10">
{NavMenu}
</div>
<ThemeToggle />
<div className="ml-auto lg:hidden">
<div className="dropdown-end dropdown" data-cy="dropdown">
<div tabIndex={0} className="m-1 cursor-pointer">

View File

@@ -1,406 +1,97 @@
"user client";
"use client";
import React from "react";
import { Switch } from "@headlessui/react";
import classNames from "classnames";
import { useRouter } from "next/navigation";
import { User, Bell } from "react-feather";
import classNames from "classnames";
import { useAuthUserContext } from "@/lib/auth/authUserContext";
import useFirebaseAuth from "@/lib/auth/useFirebaseAuth";
import { ImageUpload, InputText } from "../widgets/inputs";
import { HeadingSubComponent } from "../widgets/text";
import ProfilePageComponentProfile from "./ProfilePageComponentProfile";
import ProfilePageComponentNotifications from "./ProfilePageComponentNotifications";
const ProfilePageComponent = () => {
const { user, loading, logOut } = useAuthUserContext();
const { profile, loading } = useAuthUserContext();
const router = useRouter();
React.useEffect(() => {
if (!loading && !profile) {
router.push("/");
}
}, [profile, loading, router]);
const [sendReminders, setSendReminders] = React.useState(false);
const subNavigation = [
{ name: "Profile", href: "#", icon: User, current: true },
{ name: "Notifications", href: "#", icon: Bell, current: false },
{ name: "profile", title: "Profile", icon: User },
{
name: "notifications",
title: "Notifications",
icon: Bell,
},
];
return (
<div className="overflow-hidden bg-white rounded-lg shadow">
<div className="divide-y divide-gray-200 lg:grid lg:grid-cols-12 lg:divide-y-0 lg:divide-x">
<aside className="py-6 lg:col-span-3">
<nav className="space-y-1">
{subNavigation.map((item) => (
<a
key={item.name}
href={item.href}
className={classNames(
item.current
? "border-teal-500 bg-teal-50 text-teal-700 hover:bg-teal-50 hover:text-teal-700"
: "border-transparent text-gray-900 hover:bg-gray-50 hover:text-gray-900",
"group flex items-center border-l-4 px-3 py-2 text-sm font-medium"
)}
aria-current={item.current ? "page" : undefined}
>
<item.icon
className={classNames(
item.current
? "text-teal-500 group-hover:text-teal-500"
: "text-gray-400 group-hover:text-gray-500",
"-ml-1 mr-3 h-6 w-6 flex-shrink-0"
)}
aria-hidden="true"
/>
<span className="truncate">{item.name}</span>
</a>
))}
</nav>
</aside>
const [selectedItem, setSelectedItem] = React.useState("profile");
const [userName, setUserName] = React.useState("");
const [password, setPassword] = React.useState("");
const [about, setAbout] = React.useState("");
const [displayName, setDisplayName] = React.useState("");
const [url, setUrl] = React.useState("");
const [image, setImage] = React.useState("");
<form
className="divide-y divide-gray-200 lg:col-span-9"
action="#"
method="POST"
>
{/* Profile section */}
<div className="px-4 py-6 sm:p-6 lg:pb-8">
<div>
<h2 className="text-lg font-medium leading-6 text-gray-900">
Profile
</h2>
<p className="mt-1 text-sm text-gray-500">
This information will be displayed publicly so be careful what
you share.
</p>
</div>
<div className="flex flex-col mt-6 lg:flex-row">
<div className="flex-grow space-y-6">
<div>
<label
htmlFor="username"
className="block text-sm font-medium text-gray-700"
React.useEffect(() => {}, [selectedItem]);
const _getView = () => {
if (loading) {
return <div>Loading</div>;
} else if (!loading && !profile) {
return <div>Rerouting</div>;
} else if (!loading && profile) {
return (
<div className="overflow-hidden rounded-lg shadow bg-base-100 text-base-content">
<h1>{selectedItem}</h1>
<div className="divide-y lg:grid lg:grid-cols-12 lg:divide-y-0 lg:divide-x">
<aside className="py-6 lg:col-span-3">
<nav className="space-y-1">
{subNavigation.map((item) => (
<a
onClick={() => setSelectedItem(item.name)}
key={item.name}
className={classNames(
item.name === selectedItem
? "border-teal-600 bg-base-100 text-teal-700 hover:text-teal-700"
: "border-transparent hover:text-base-300",
"group flex cursor-pointer items-center border-l-4 px-3 py-2 text-sm font-medium hover:bg-accent"
)}
aria-current={item.name ? "page" : undefined}
>
Username
</label>
<div className="flex mt-1 rounded-md shadow-sm">
<span className="inline-flex items-center px-3 text-gray-500 border border-r-0 border-gray-300 rounded-l-md bg-gray-50 sm:text-sm">
workcation.com/
</span>
<input
type="text"
name="username"
id="username"
autoComplete="username"
className="flex-grow block w-full min-w-0 border-gray-300 rounded-none rounded-r-md focus:border-sky-500 focus:ring-sky-500 sm:text-sm"
defaultValue={user.handle}
/>
</div>
</div>
<div>
<label
htmlFor="about"
className="block text-sm font-medium text-gray-700"
>
About
</label>
<div className="mt-1">
<textarea
id="about"
name="about"
rows={3}
className="block w-full mt-1 border border-gray-300 rounded-md shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm"
defaultValue={""}
/>
</div>
<p className="mt-2 text-sm text-gray-500">
Brief description for your profile. URLs are hyperlinked.
</p>
</div>
</div>
<div className="flex-grow mt-6 lg:mt-0 lg:ml-6 lg:flex-shrink-0 lg:flex-grow-0">
<p
className="text-sm font-medium text-gray-700"
aria-hidden="true"
>
Photo
</p>
<div className="mt-1 lg:hidden">
<div className="flex items-center">
<div
className="flex-shrink-0 inline-block w-12 h-12 overflow-hidden rounded-full"
<item.icon
className={classNames(
item.name === selectedItem
? "text-teal-500 group-hover:text-base-100"
: "text-base-content group-hover:text-base-100",
"-ml-1 mr-3 h-6 w-6 flex-shrink-0"
)}
aria-hidden="true"
>
<img
className="w-full h-full rounded-full"
src={user.imageUrl}
alt=""
/>
</div>
<div className="ml-5 rounded-md shadow-sm">
<div className="relative flex items-center justify-center px-3 py-2 border border-gray-300 rounded-md group focus-within:ring-2 focus-within:ring-sky-500 focus-within:ring-offset-2 hover:bg-gray-50">
<label
htmlFor="mobile-user-photo"
className="relative text-sm font-medium leading-4 text-gray-700 pointer-events-none"
>
<span>Change</span>
<span className="sr-only"> user photo</span>
</label>
<input
id="mobile-user-photo"
name="user-photo"
type="file"
className="absolute w-full h-full border-gray-300 rounded-md opacity-0 cursor-pointer"
/>
</div>
</div>
</div>
</div>
<div className="relative hidden overflow-hidden rounded-full lg:block">
<img
className="relative w-40 h-40 rounded-full"
src={user.imageUrl}
alt=""
/>
<label
htmlFor="desktop-user-photo"
className="absolute inset-0 flex items-center justify-center w-full h-full text-sm font-medium text-white bg-black bg-opacity-75 opacity-0 focus-within:opacity-100 hover:opacity-100"
>
<span>Change</span>
<span className="sr-only"> user photo</span>
<input
type="file"
id="desktop-user-photo"
name="user-photo"
className="absolute inset-0 w-full h-full border-gray-300 rounded-md opacity-0 cursor-pointer"
/>
</label>
</div>
</div>
</div>
<span className="truncate">{item.title}</span>
</a>
))}
</nav>
</aside>
<div className="grid grid-cols-12 gap-6 mt-6">
<div className="col-span-12 sm:col-span-6">
<label
htmlFor="first-name"
className="block text-sm font-medium text-gray-700"
>
First name
</label>
<input
type="text"
name="first-name"
id="first-name"
autoComplete="given-name"
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:border-sky-500 focus:outline-none focus:ring-sky-500 sm:text-sm"
/>
</div>
<div className="col-span-12 sm:col-span-6">
<label
htmlFor="last-name"
className="block text-sm font-medium text-gray-700"
>
Last name
</label>
<input
type="text"
name="last-name"
id="last-name"
autoComplete="family-name"
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:border-sky-500 focus:outline-none focus:ring-sky-500 sm:text-sm"
/>
</div>
<div className="col-span-12">
<label
htmlFor="url"
className="block text-sm font-medium text-gray-700"
>
URL
</label>
<input
type="text"
name="url"
id="url"
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:border-sky-500 focus:outline-none focus:ring-sky-500 sm:text-sm"
/>
</div>
<div className="col-span-12 sm:col-span-6">
<label
htmlFor="company"
className="block text-sm font-medium text-gray-700"
>
Company
</label>
<input
type="text"
name="company"
id="company"
autoComplete="organization"
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:border-sky-500 focus:outline-none focus:ring-sky-500 sm:text-sm"
/>
</div>
<div className="p-4 divide-y lg:col-span-9">
{selectedItem === "profile" ? (
<ProfilePageComponentProfile />
) : (
<ProfilePageComponentNotifications />
)}
</div>
</div>
{/* Privacy section */}
<div className="pt-6 divide-y divide-gray-200">
<div className="px-4 sm:px-6">
<div>
<h2 className="text-lg font-medium leading-6 text-gray-900">
Privacy
</h2>
<p className="mt-1 text-sm text-gray-500">
Ornare eu a volutpat eget vulputate. Fringilla commodo amet.
</p>
</div>
<ul role="list" className="mt-2 divide-y divide-gray-200">
<Switch.Group
as="li"
className="flex items-center justify-between py-4"
>
<div className="flex flex-col">
<Switch.Label
as="p"
className="text-sm font-medium text-gray-900"
passive
>
Available to hire
</Switch.Label>
<Switch.Description className="text-sm text-gray-500">
Nulla amet tempus sit accumsan. Aliquet turpis sed sit
lacinia.
</Switch.Description>
</div>
<Switch
checked={availableToHire}
onChange={setAvailableToHire}
className={classNames(
availableToHire ? "bg-teal-500" : "bg-gray-200",
"relative ml-4 inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
)}
>
<span
aria-hidden="true"
className={classNames(
availableToHire ? "translate-x-5" : "translate-x-0",
"inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
)}
/>
</Switch>
</Switch.Group>
<Switch.Group
as="li"
className="flex items-center justify-between py-4"
>
<div className="flex flex-col">
<Switch.Label
as="p"
className="text-sm font-medium text-gray-900"
passive
>
Make account private
</Switch.Label>
<Switch.Description className="text-sm text-gray-500">
Pharetra morbi dui mi mattis tellus sollicitudin cursus
pharetra.
</Switch.Description>
</div>
<Switch
checked={privateAccount}
onChange={setPrivateAccount}
className={classNames(
privateAccount ? "bg-teal-500" : "bg-gray-200",
"relative ml-4 inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
)}
>
<span
aria-hidden="true"
className={classNames(
privateAccount ? "translate-x-5" : "translate-x-0",
"inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
)}
/>
</Switch>
</Switch.Group>
<Switch.Group
as="li"
className="flex items-center justify-between py-4"
>
<div className="flex flex-col">
<Switch.Label
as="p"
className="text-sm font-medium text-gray-900"
passive
>
Allow commenting
</Switch.Label>
<Switch.Description className="text-sm text-gray-500">
Integer amet, nunc hendrerit adipiscing nam. Elementum ame
</Switch.Description>
</div>
<Switch
checked={allowCommenting}
onChange={setAllowCommenting}
className={classNames(
allowCommenting ? "bg-teal-500" : "bg-gray-200",
"relative ml-4 inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
)}
>
<span
aria-hidden="true"
className={classNames(
allowCommenting ? "translate-x-5" : "translate-x-0",
"inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
)}
/>
</Switch>
</Switch.Group>
<Switch.Group
as="li"
className="flex items-center justify-between py-4"
>
<div className="flex flex-col">
<Switch.Label
as="p"
className="text-sm font-medium text-gray-900"
passive
>
Allow mentions
</Switch.Label>
<Switch.Description className="text-sm text-gray-500">
Adipiscing est venenatis enim molestie commodo eu gravid
</Switch.Description>
</div>
<Switch
checked={allowMentions}
onChange={setAllowMentions}
className={classNames(
allowMentions ? "bg-teal-500" : "bg-gray-200",
"relative ml-4 inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
)}
>
<span
aria-hidden="true"
className={classNames(
allowMentions ? "translate-x-5" : "translate-x-0",
"inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
)}
/>
</Switch>
</Switch.Group>
</ul>
</div>
<div className="flex justify-end px-4 py-4 mt-4 sm:px-6">
<button
type="button"
className="inline-flex justify-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
>
Cancel
</button>
<button
type="submit"
className="inline-flex justify-center px-4 py-2 ml-5 text-sm font-medium text-white border border-transparent rounded-md shadow-sm bg-sky-700 hover:bg-sky-800 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
>
Save
</button>
</div>
</div>
</form>
</div>
</div>
);
</div>
);
} else {
return (
<div>
<h1>This is weird</h1>
</div>
);
}
};
return _getView();
};
export default ProfilePageComponent;

View File

@@ -0,0 +1,47 @@
import React from "react";
import { HeadingSubComponent } from "@/components/widgets/text";
import { InputText } from "@/components/widgets/inputs";
import { PhoneNumberContextImpl } from "twilio/lib/rest/lookups/v2/phoneNumber";
import { PhoneNumber } from "../widgets/notifications";
const ProfilePageComponentNotifications = () => {
return (
<form className="space-y-8 divide-y ">
<div className="space-y-8 divide-y sm:space-y-5">
<div>
<div>
<h3 className="text-lg font-medium leading-6 ">Notifications</h3>
<p className="max-w-2xl mt-1 text-sm ">
Here you can setup various different forms of notifications
</p>
</div>
<div className="mt-6 space-y-6 sm:mt-5 sm:space-y-5">
<div className="space-x-3 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-t sm:pt-5">
<HeadingSubComponent
title="Phone number"
subHeading="We'll try to send you a WhatsApp message when a show is about to start"
/>
<div className="mt-1 sm:col-span-2 sm:mt-0">
<div className="flex max-w-lg rounded-md shadow-sm">
<PhoneNumber
phoneNumber="12354"
setPhoneNumber={(value) =>
console.log(
"ProfilePageComponentNotifications",
"setPhoneNumber",
value
)
}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
);
};
export default ProfilePageComponentNotifications;

View File

@@ -0,0 +1,170 @@
"use client";
import React from "react";
import { InputText } from "../widgets/inputs";
import { HeadingSubComponent } from "../widgets/text";
const ProfilePageComponentProfile = () => {
const [sendReminders, setSendReminders] = React.useState(false);
const [userName, setUserName] = React.useState("");
const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
const [about, setAbout] = React.useState("");
const [displayName, setDisplayName] = React.useState("");
const [url, setUrl] = React.useState("");
const [image, setImage] = React.useState("");
return (
<form className="space-y-8 divide-y ">
<div className="space-y-8 divide-y sm:space-y-5">
<div>
<div>
<h3 className="text-lg font-medium leading-6 ">Profile</h3>
<p className="max-w-2xl mt-1 text-sm ">
This information will be displayed publicly so be careful what you
share.
</p>
</div>
<div className="mt-6 space-y-6 sm:mt-5 sm:space-y-5">
<div className="space-x-3 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-t sm:pt-5">
<HeadingSubComponent
title="Username"
subHeading="The username that you would like to use to login to the site. This could be your email address"
/>
<div className="mt-1 sm:col-span-2 sm:mt-0">
<div className="flex max-w-lg rounded-md shadow-sm">
<InputText
id="username"
labelTitle="Username"
defaultValue={userName}
updateFormValue={(v) => setUserName(v)}
showLabel={false}
/>
</div>
</div>
</div>
<div className="space-x-3 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-t sm:pt-5">
<HeadingSubComponent
title="Email address"
subHeading="In case we need to get in touch with you"
/>
<div className="mt-1 sm:col-span-2 sm:mt-0">
<div className="flex max-w-lg rounded-md shadow-sm">
<InputText
id="email"
type="email"
labelTitle="Email address"
defaultValue={email}
updateFormValue={(v) => setEmail(v)}
showLabel={false}
/>
</div>
</div>
</div>
<div className="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-t sm:pt-5">
<HeadingSubComponent
title="About"
subHeading="Tell us a little bit about yourself.. but not too much"
/>
<div className="mt-1 sm:col-span-2 sm:mt-0">
<InputText
id="about"
type="textarea"
labelTitle="About"
defaultValue={about}
updateFormValue={(v) => setAbout(v)}
showLabel={false}
/>
<p className="mt-2 text-sm ">
Write a few sentences about yourself.
</p>
</div>
</div>
<div className="sm:grid sm:grid-cols-3 sm:items-center sm:gap-4 sm:border-t sm:pt-5">
<HeadingSubComponent
title="Photo"
subHeading="Upload a picture to distinguish you from the rest"
/>
<div className="mt-1 sm:col-span-2 sm:mt-0">
<div className="flex items-center">
<span className="w-12 h-12 overflow-hidden rounded-full">
<svg
className="w-full h-full "
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
</span>
<button
type="button"
className="px-3 py-2 ml-5 text-sm font-medium leading-4 border rounded-md shadow-sm hover: focus:outline-none focus:ring-2 focus:ring-offset-2"
>
Change
</button>
</div>
</div>
</div>
<div className="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-t sm:pt-5">
<HeadingSubComponent
title="Cover photo"
subHeading="Upload a wide photo for the top of your profile page"
/>
<div className="mt-1 sm:col-span-2 sm:mt-0">
<div className="flex justify-center max-w-lg px-6 pt-5 pb-6 border-2 border-dashed rounded-md">
<div className="space-y-1 text-center">
<svg
className="w-12 h-12 mx-auto "
stroke="currentColor"
fill="none"
viewBox="0 0 48 48"
aria-hidden="true"
>
<path
d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<div className="flex text-sm ">
<label
htmlFor="file-upload"
className="relative font-medium rounded-md cursor-pointer te focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2"
>
<span>Upload a file</span>
<input
id="file-upload"
name="file-upload"
type="file"
className="sr-only"
/>
</label>
<p className="pl-1">or drag and drop</p>
</div>
<p className="text-xs ">PNG, JPG, GIF up to 10MB</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="pt-5">
<div className="flex justify-end space-x-2">
<button type="button" className="btn-warning btn">
Cancel
</button>
<button type="submit" className="btn-success btn">
Save
</button>
</div>
</div>
</form>
);
};
export default ProfilePageComponentProfile;

View File

@@ -1,48 +0,0 @@
import React from "react";
interface IInputTextProps {
labelTitle: string;
labelStyle?: string;
type: string;
containerStyle: string;
defaultValue: string;
placeholder?: string;
updateFormValue: (type: string, value: string) => void;
updateType: string;
}
const InputText = ({
labelTitle,
labelStyle = "",
type,
containerStyle,
defaultValue,
placeholder = "",
updateFormValue,
updateType,
}: IInputTextProps) => {
const [value, setValue] = React.useState(defaultValue);
const updateInputValue = (val: string) => {
setValue(val);
updateFormValue(updateType, val);
};
return (
<div className={`form-control w-full ${containerStyle}`}>
<label className="label">
<span className={"label-text text-base-content " + labelStyle}>
{labelTitle}
</span>
</label>
<input
type={type || "text"}
value={value}
placeholder={placeholder || ""}
onChange={(e) => updateInputValue(e.target.value)}
className="w-full input-bordered input "
/>
</div>
);
};
export default InputText;

View File

@@ -5,10 +5,10 @@ import React from "react";
import { MdAddAlarm } from "react-icons/md";
import { error, success, warning } from "./toast/toastService";
const RemindMeButton = ({ show }: { show: Show }) => {
const { user } = useFirebaseAuth();
const RemindMeButton = ({ showId }: { showId: string }) => {
const { profile } = useFirebaseAuth();
const createShowReminder = async () => {
if (user?.uid) {
if (profile?.id) {
var response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/reminders`,
{
@@ -17,8 +17,8 @@ const RemindMeButton = ({ show }: { show: Show }) => {
"Content-Type": "application/json",
},
body: JSON.stringify({
userId: user?.uid,
showId: show.id,
userId: profile?.id,
showId: profile?.id,
}),
}
);

View File

@@ -1,6 +1,4 @@
import ErrorText from "./ErrorText";
import InputText from "./InputText";
import RemindMeButton from "./RemindMeButton";
import ToastService from "./toast/toastService";
export { ErrorText, InputText, RemindMeButton, ToastService };
export { ErrorText, RemindMeButton };

View File

@@ -0,0 +1,45 @@
import React from "react";
import Dropzone, { DropzoneRef, useDropzone } from "react-dropzone";
const ImageUpload = () => {
const dropzoneRef = React.createRef<DropzoneRef>();
const openDialog = () => {
if (dropzoneRef.current) {
dropzoneRef.current.open();
}
};
return (
<Dropzone
accept={{
"image/png": [".png"],
"image/jpg": [".jpg", ".jpeg"],
}}
maxFiles={1}
ref={dropzoneRef}
>
{({ getRootProps, getInputProps, acceptedFiles }) => {
return (
<div className="container">
<div {...getRootProps({ className: "dropzone" })}>
{acceptedFiles?.length ? (
<div id="preview">
{acceptedFiles[0] && (
<img
className="object-cover"
src={URL.createObjectURL(acceptedFiles[0])}
/>
)}
</div>
) : (
<div id="drop">
<div className="flex items-center justify-center w-full"></div>
</div>
)}
</div>
</div>
);
}}
</Dropzone>
);
};
export default ImageUpload;

View File

@@ -0,0 +1,63 @@
import React from "react";
interface IInputTextProps {
id: string;
labelTitle: string;
labelStyle?: string;
type?: string;
containerStyle?: string;
defaultValue: string;
placeholder?: string;
showLabel?: boolean;
updateFormValue: (value: string) => void;
}
const InputText = ({
id,
labelTitle,
labelStyle,
type,
containerStyle,
defaultValue,
placeholder,
updateFormValue,
showLabel = true,
}: IInputTextProps) => {
const [value, setValue] = React.useState(defaultValue);
const updateInputValue = (val: string) => {
setValue(val);
updateFormValue(val);
};
const _getId = () => (type === "text" ? `inp_${id}` : `ta_${id}`);
const _getInput = () =>
type === "textarea" ? (
<textarea
id={_getId()}
name={_getId()}
rows={3}
className="w-full h-24 textarea-bordered textarea"
defaultValue={defaultValue}
/>
) : (
<input
id={_getId()}
type={type || "text"}
value={value}
placeholder={placeholder || ""}
onChange={(e) => updateInputValue(e.target.value)}
className="w-full input-bordered input"
/>
);
return (
<React.Fragment>
{showLabel && (
<label className="label" htmlFor={_getId()}>
<span className="label-text">{labelTitle}</span>
</label>
)}
{_getInput()}
</React.Fragment>
);
};
export default InputText;

View File

@@ -0,0 +1,5 @@
import ImageUpload from "./ImageUpload";
import InputText from "./InputText";
export { ImageUpload };
export { InputText };

View File

@@ -0,0 +1,23 @@
import React from "react";
import { InputText } from "../inputs";
interface PhoneNumberNotificationControlProps {
phoneNumber: string;
setPhoneNumber: (number: string) => void;
}
const PhoneNumberNotificationControl = ({
phoneNumber,
setPhoneNumber,
}: PhoneNumberNotificationControlProps) => {
return (
<InputText
showLabel={false}
type="tel"
defaultValue="phoneNumber"
labelTitle="Phone number"
updateFormValue={(value) => setPhoneNumber(value)}
id="phone"
/>
);
};
export default PhoneNumberNotificationControl;

View File

@@ -0,0 +1,23 @@
import React from "react";
import { InputText } from "../inputs";
interface ISignalNotificationProps {
phoneNumber: string;
setPhoneNumber: (number: string) => void;
}
const SignalNotification = ({
phoneNumber,
setPhoneNumber,
}: ISignalNotificationProps) => {
return (
<InputText
showLabel={false}
type="tel"
defaultValue="phoneNumber"
labelTitle="Phone number"
updateFormValue={(value) => setPhoneNumber(value)}
id="phone"
/>
);
};
export default SignalNotification;

View File

@@ -0,0 +1,4 @@
import PhoneNumber from "./PhoneNumber";
import SignalNotification from "./SignalNotification";
export { PhoneNumber, SignalNotification };

View File

@@ -0,0 +1,19 @@
import React from "react";
export interface IHeadingSubComponentProps {
title: string;
subHeading: string;
}
const HeadingSubComponent = ({
title,
subHeading,
}: IHeadingSubComponentProps) => {
return (
<div className="flex flex-col ml-3">
<span className="text-lg font-medium leading-6">{title}</span>
<span className="mt-1 text-xs">{subHeading}</span>
</div>
);
};
export default HeadingSubComponent;

View File

@@ -0,0 +1,3 @@
import HeadingSubComponent from "./HeadingSubComponent";
export { HeadingSubComponent };

View File

@@ -0,0 +1,3 @@
import { error, success, warning } from "./toastService";
export { success, warning, error };

View File

@@ -1,40 +1,24 @@
import React, { createContext, useContext, Context } from "react";
import useFirebaseAuth from "@/lib/auth/useFirebaseAuth";
import { User } from "@/models";
import { Profile } from "@/models";
interface IAuthUserContext {
user: User | undefined;
loading: boolean;
signIn: (email: string, password: string) => {},
signUp: (email: string, password: string) => {},
logOut: () => {},
signInWithGoogle: () => {},
signInWithTwitter: () => {},
signInWithFacebook: () => {}
profile: Profile | undefined,
logOut: () => Promise<boolean>;
}
const authUserContext
= createContext<IAuthUserContext>({
user: undefined,
const authUserContext = createContext<IAuthUserContext>({
loading: true,
signIn: async (email: string, password: string) => {
},
signUp: async (email: string, password: string) => {
},
logOut: async () => {
},
signInWithGoogle: async () => {
},
signInWithTwitter: async () => {
},
signInWithFacebook: async () => {
}
profile: undefined,
logOut: () => Promise.resolve(false)
});
export function AuthUserProvider({ children }: { children: React.ReactNode }) {
const auth
= useFirebaseAuth();
return <authUserContext.Provider value={auth}>{children}</authUserContext.Provider>;
const { loading, profile, logOut } = useFirebaseAuth();
return (
<authUserContext.Provider value={{ loading, profile, logOut }}>{children}</authUserContext.Provider>
);
}
export const useAuthUserContext = () => useContext(authUserContext);

View File

@@ -12,35 +12,43 @@ import {
} from "firebase/auth";
import { app } from "./firebase";
import { useRouter } from "next/navigation";
import { User } from "@/models";
import { Profile } from "@/models";
import { FirebaseAuth } from "@firebase/auth-types";
const formatAuthUser = (user: User) => ({
uid: user.uid,
email: user.email
});
export default function useFirebaseAuth() {
const [profile, setProfile] = useState<Profile | undefined>();
const auth = getAuth(app);
const router = useRouter();
const [user, setUser] = useState<User | undefined>(undefined);
const [loading, setLoading] = useState(true);
const authStateChanged = async (authState: any) => {
if (!authState) {
const getUserProfile = (): Profile | undefined => {
if (auth.currentUser !== null) {
// The user object has basic properties such as display name, email, etc.
// Going forward we may look this up from the user table in firestore
const profile = new Profile(
auth.currentUser.uid,
auth.currentUser.email,
auth.currentUser.displayName,
auth.currentUser.photoURL,
auth.currentUser.emailVerified
);
setProfile(profile);
return profile;
}
};
const authStateChanged = async (user: any) => {
if (user) {
setLoading(false);
const profile = getUserProfile();
setProfile(profile);
return;
}
setLoading(true);
var formattedUser = formatAuthUser(authState);
setUser(formattedUser);
setLoading(false);
};
const clear = () => {
setUser(undefined);
setProfile(undefined);
setLoading(true);
};
@@ -52,62 +60,37 @@ export default function useFirebaseAuth() {
const logOut = () =>
signOut(auth).then(clear);
const signInWithGoogle = async () => {
const provider = new GoogleAuthProvider();
provider.setCustomParameters({ prompt: "select_account" });
const _processSignIn = async (provider: any) => {
try {
const result = await signInWithPopup(auth, provider);
const credential = GoogleAuthProvider.credentialFromResult(result);
if (credential) {
const token = credential.accessToken;
// const user = result.user;
if (result.user) {
const profile = getUserProfile();
setProfile(profile);
router.push("/");
}
router.push("/");
} catch (error: any) {
const errorCode = error.code;
const errorMessage = error.message;
const email = error.email;
const credential = GoogleAuthProvider.credentialFromError(error);
}
};
const signInWithTwitter = () => {
// const provider = new TwitterAuthProvider();
//
// return auth.signInWithPopup(auth, provider)
// .then((result) => {
// const credential = TwitterAuthProvider.credentialFromResult(result);
// if (credential) {
// const token = credential.accessToken;
// const user = result.user;
// }
// router.push("/");
// })
// .catch((error) => {
// const errorCode = error.code;
// const errorMessage = error.message;
// const email = error.email;
// const credential = GoogleAuthProvider.credentialFromError(error);
// });
const signInWithGoogle = async () => {
debugger
const provider = new GoogleAuthProvider();
provider.setCustomParameters({ prompt: "select_account" });
provider.addScope("https://www.googleapis.com/auth/userinfo.profile");
await _processSignIn(provider);
};
const signInWithFacebook = () => {
const signInWithTwitter = async () => {
const provider = new TwitterAuthProvider();
await _processSignIn(provider);
};
const signInWithFacebook = async () => {
const provider = new FacebookAuthProvider();
return signInWithPopup(auth, provider)
.then((result) => {
const credential = TwitterAuthProvider.credentialFromResult(result);
if (credential) {
const token = credential.accessToken;
const user = result.user;
}
router.push("/");
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
const email = error.email;
const credential = GoogleAuthProvider.credentialFromError(error);
});
await _processSignIn(provider);
};
useEffect(() => {
@@ -116,13 +99,14 @@ export default function useFirebaseAuth() {
}, []);
return {
user,
profile,
loading,
signIn,
signUp,
logOut,
signInWithGoogle,
signInWithTwitter,
signInWithFacebook
signInWithFacebook,
getUserProfile
};
}

View File

@@ -1,4 +1,4 @@
export const defaults = {
defaultTheme: "bumblebee",
defaultDarkTheme: "dark",
defaultTheme: "fantasy",
defaultDarkTheme: "luxury",
};

View File

@@ -1,8 +1,8 @@
const getMonthName = (date: Date) => {
return date.toLocaleString("default", { month: "short" });
const getMonthName = (date: string) => {
return new Date(date).toLocaleString("default", { month: "short" });
};
const getTime = (date: Date) =>
date.toLocaleTimeString("en-IE", { timeStyle: "short" });
const getTime = (date: string) =>
new Date(date).toLocaleTimeString("en-IE", { timeStyle: "short" });
const getStartOfToday = (admin: any) => {
const now = new Date();

View File

@@ -1,11 +1,11 @@
import User from "./user";
import Profile from "./profile";
import Show from "./show";
import Reminder from "./reminder";
import Notification from "./notification";
import type { RemindersProcessed } from "./processes";
export {
User,
Profile,
Show,
Reminder,
Notification,

15
src/models/profile.ts Normal file
View File

@@ -0,0 +1,15 @@
export default class Profile {
id: string;
email: string | null;
displayName: string | null;
photoURL: string | null;
emailVerified: boolean;
constructor(id: string, email: string | null, displayName: string | null, photoURL: string | null, emailVerified: boolean) {
this.id = id;
this.email = email;
this.displayName = displayName;
this.photoURL = photoURL;
this.emailVerified = emailVerified;
}
}

View File

@@ -5,7 +5,7 @@ export default class Reminder {
userId: string;
showId: string;
notifications: Notification[];
created: Date;
created: Date
constructor(id: string,
userId: string,

View File

@@ -1,13 +1,13 @@
export default class Show {
id: string;
title: string;
date: Date;
date: string;
creator: string;
constructor(id: string, title: string, date: Date, creator: string) {
this.id = id;
this.title = title;
this.date = date;
this.date = date.toString();
this.creator = creator;
}

View File

@@ -1,9 +0,0 @@
export default class User {
uid: string;
email: string
constructor(uid: string, email: string) {
this.uid = uid;
this.email = email;
}
}

View File

@@ -11,63 +11,7 @@ module.exports = {
// ],
plugins: [require("daisyui")],
daisyui: {
themes: [
{
radioTheme: {
primary: "#00B8F0",
"primary-focus": "#009de0",
"primary-content": "#ffffff",
secondary: "#f03800",
"secondary-focus": "#e22f00",
"secondary-content": "#ffffff",
accent: "#00f0b0",
"accent-focus": "#00e28a",
"accent-content": "#ffffff",
neutral: "#3d4451",
"neutral-focus": "#2a2e37",
"neutral-content": "#ffffff",
"base-100": "#ffffff",
"base-200": "#767676",
"base-300": "#d1d5db",
"base-content": "#1f2937",
info: "#2094f3" /* Info */,
success: "#009485" /* Success */,
warning: "#ff9900" /* Warning */,
error: "#ff5724" /* Error */,
},
dark: {
primary: "#00B8F0",
"primary-focus": "#009de0",
"primary-content": "#ffffff",
secondary: "#f03800",
"secondary-focus": "#e22f00",
"secondary-content": "#ffffff",
accent: "#00f0b0",
"accent-focus": "#00e28a",
"accent-content": "#ffffff",
neutral: "#3d4451",
"neutral-focus": "#2a2e37",
"neutral-content": "#ffffff",
"base-100": "#2A2E37",
"base-200": "#EBECF0",
"base-300": "#16181D",
"base-content": "#EBECF0",
info: "#2094f3",
success: "#009485",
warning: "#ff9900",
error: "#ff5724",
},
},
],
themes: ["fantasy", "luxury"],
darkTheme: "luxury",
},
};

244
yarn.lock
View File

@@ -422,10 +422,10 @@
resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.9.0.tgz#9340bce56560a8bdba1d25d6281d4bfc397450dc"
integrity sha512-BpiZLBWdLFw+qFel9p3Zs1jD6QmH7Ii4aTDu6+vx8ShdidChZUXqDhYJly4ZjSgQh54miXbBgBrk0S+jTIh/Qg==
"@google-cloud/local-auth@2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@google-cloud/local-auth/-/local-auth-2.1.0.tgz#5cb441e5016ce95996b14522e06fb4d9896a6ed0"
integrity sha512-ymZ1XuyKcRcro0aiMYz3hVGbZ+QZmN5V1Eyjvw2k1xqq76PwmDer0DIPxdxkLzfW9Inr8+g+MS9t9fZ7dOlTOQ==
"@google-cloud/local-auth@2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@google-cloud/local-auth/-/local-auth-2.1.1.tgz#fa790813cd8e45402a2681ff662c62f11bdb0c4c"
integrity sha512-tOJ73TSyPxelUEVN2AdHVzFG857U5i3wZHMUGgm6wRtz9WN4O3D761eYORB9jXfIggA3+v5BUw+VIE5wAKHhkg==
dependencies:
arrify "^2.0.1"
google-auth-library "^8.0.2"
@@ -488,10 +488,10 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@next/env@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.1.5.tgz#72b24d3726a6b752be6b7b9a937f7af31b3ce410"
integrity sha512-0Ry4NhJy6qLbXhvxPRUQ1H6RzgtryGdUto7hfgAK0Iw/bScgeVjwLZdfhm2iT7qsOS32apo9cWzLCxjc6iGPsA==
"@next/env@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.2.0.tgz#1a597a885ce11860446c88e1098fd517dc0e84b1"
integrity sha512-yv9oaRVa+AxFa27uQOVecS931NrE+GcQSqcL2HaRxL8NunStLtPiyNm/VixvdzfiWLabMz4dXvbXfwCNaECzcw==
"@next/eslint-plugin-next@13.1.5":
version "13.1.5"
@@ -500,75 +500,75 @@
dependencies:
glob "7.1.7"
"@next/font@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/font/-/font-13.1.5.tgz#9e47e5986173ffab2c3300ac1c63bc39887dfe64"
integrity sha512-6M5R6yC3JkdJiqo/YJxDp6+0vDn0smXOAzl8uHt4qmDS2u53ji/19K0HM51d+5kg8xntDi+N2hw7YjaU9inkNA==
"@next/font@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/font/-/font-13.2.0.tgz#677b3fc67243bccbae94d7d1e96a494be98206c4"
integrity sha512-pWoegIxqegV+9+gFmRCZao6xhA2m3kKS34lMXqShJ5ibRuyHkP/tfDE82LzYZmVQ3p51ZrkwTugNwy/ohiE2cA==
"@next/swc-android-arm-eabi@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.5.tgz#0ea6f76754562ab8092efe7e492906790261b7cb"
integrity sha512-QAEf3YM9U0qWVQTxgF3Tsh4OeCN1i9Smsf6cVlwZsPzoLyj2nQ879joCoN+ONqDknkBgG6OG/ajefywL3jw9Cg==
"@next/swc-android-arm-eabi@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.0.tgz#241d007fdb2f06f70ab21d5a333e08a29de9cd7f"
integrity sha512-VMetUwBWtDBGzNiOkhiWTP+99ZYW5NVRpIGlUsldEtY8IQIqleaUgW9iamsO0kDSjhWNdCQCB+xu5HcCvmDTww==
"@next/swc-android-arm64@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.1.5.tgz#8d4a91d77811c6c7057a41f4f32ecee1ac963981"
integrity sha512-ZmtGPTghRuT5YKL0nNcC2bBVSiG1O0is16eIZ2rWSP/hRW64ZCcAew6pxw2rihntNp22UfequjSTHd91WE/tyQ==
"@next/swc-android-arm64@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.2.0.tgz#924e79197f094a12ac3409b6a416f84c2f74341d"
integrity sha512-fAiP54Om3fSj5aKntxEvW5fWzyMUzLzjFrHuUt5jBnTRWM4QikhLy547OZDoxycyk4GoQVHmNMSA3hILsrV/dQ==
"@next/swc-darwin-arm64@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.5.tgz#3f206d22201c6500acce3a9274a807fb07878565"
integrity sha512-aeFXK+M/zmG/CNdMJ0tGNs0MWcLueUe7vZ2V6fa+2yz/ZgYJLI7fEfFvVh1p1yBMzupSbZDowvMuCSFTaeg3MA==
"@next/swc-darwin-arm64@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.0.tgz#bfd3dfe90903b3bbf81f617f2b1d4f8b9e20e8aa"
integrity sha512-F4zbvPnq3zCTqyyM6WN8ledazzJx3OrxIdc2ewnqnfk6tjBZ/aq1M27GhEfylGjZG1KvbtJCxUqi7dR/6R94bA==
"@next/swc-darwin-x64@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.5.tgz#3b0775ed190a6b35cd0ba61510dcd133dcb8c4bf"
integrity sha512-6mPX0GNRg8NzjV70at8I8pD9YBnPHDpxJCoMuIqysdTjtQhd09Xk6GUhquNhp1kEJzzVk7OW5l2ch4XIJjtY3A==
"@next/swc-darwin-x64@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.0.tgz#3d159bb2889f093d173546a6e5edd6260df7e156"
integrity sha512-Y9+fB7TLAAnkCZQXWjwJg5bi1pT5NuNkI+HoKYp26U1J0SxW5vZWFGc31WFmmHIz3wA0zlaQfRa4mF7cpZL5yw==
"@next/swc-freebsd-x64@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.5.tgz#a9f2b39434b52867860afbd32638f9742c45c82a"
integrity sha512-nR4a/SNblG0w8hhYRflTZjk4yD99ld18w/FCftw99ziw8sgciBlOXRICJIiRIaMRU8UH7QLSgBOQVnfNcVNKMA==
"@next/swc-freebsd-x64@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.0.tgz#33877ad933e1b3d7776dfb060f4e3b55f675523e"
integrity sha512-b9bCLlfznbV6e6Vg9wKYZJs7Uz8z/Py9105MYq95a3JlHiI3e/fvBpm1c7fe5QlvWJlqyNav6Clyu1W+lDk+IQ==
"@next/swc-linux-arm-gnueabihf@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.5.tgz#4ae5dcdea5aa5cb6b9ce14bbf86e3afe7dc3df1a"
integrity sha512-EzkltCVKg3gUzamoeKPhGeSgXTTLAhSzc7v/+g1Y+HQa7JKMrlzdRkrJf+H4LJXcz7lnxgNKHGRyZBSXnmJKJw==
"@next/swc-linux-arm-gnueabihf@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.0.tgz#31b81ff368e5337019f858c4a0d7ae7f80310728"
integrity sha512-jY/2JjDVVyktzRtMclAIVLgOxk5Ut9NKu8kKMCPdKMf9/ila37UpRfIh2fOXtRhv8AK7Lq/iSI/v2vjopZxZgQ==
"@next/swc-linux-arm64-gnu@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.5.tgz#92d816a430390642aa1ce1969a255b6a0b2d9833"
integrity sha512-E7HMkdoxStmTUJU4KzBUU4vZ5DHT4Gd327tC3KFZS5lda0NRerJAOCfsRg+fBj22FvCb1UWsX6XI+weL6xhyeQ==
"@next/swc-linux-arm64-gnu@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.0.tgz#e46bd73d1ccc38be46009b88dc87df88d8c44fa1"
integrity sha512-EKjWU3/lSBhOwPQRQLbySUnATnXygCjGd8ag3rP6d7kTIhfuPO4pY+DYW+wHOt5qB1ULNRmW0sXZ/ZKnQrVszw==
"@next/swc-linux-arm64-musl@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.5.tgz#b44ba6866802ee0f6d655e7184b7c2f29485219f"
integrity sha512-qlO0Fd3GQwJS6YpbF9NyL5NGHVZ43dKtZDC/jP4vdeMIYDtSu13HcY/nmA1NdW+RpMwDxSCpx4WKsCCEZGIX8Q==
"@next/swc-linux-arm64-musl@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.0.tgz#54a4f0cc1431f3e4e24a5e017e473a5fc761b33b"
integrity sha512-T5R9r23Docwo6PYZRzndeFB5WUN3+smMbyk25K50MAngCiSydr82/YfAetcp7Ov7Shp4a8xXP9DHDIsBas6wbQ==
"@next/swc-linux-x64-gnu@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.5.tgz#f70afe2654d8ca6e488964ed0ebef11f38d56675"
integrity sha512-GftSBFAay2nocGl+KNqFsj6EVSvomaM/bp86hzezbKsTwQmu76PjOCVcejI1gE+4k7f5zPDgCuorF6F04BV0HQ==
"@next/swc-linux-x64-gnu@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.0.tgz#1c17a6121846decac2d701a040649f8f764ac671"
integrity sha512-FeXTc2KFvUSnTJmkpNMKoBHmNA1Ujr3QdfcKnVm/gXWqK+rfuEhAiRNOo+6mPcQ0noEge1j8Ai+W1LTbdDwPZQ==
"@next/swc-linux-x64-musl@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.5.tgz#6e4aa45a6ee1cea7e6c3295dfde69250afd4c714"
integrity sha512-UD+3lxU4yuAjd+uBkCDfBpAcbGAVfEcE8mX/efIxUGIImmzN0QzgTHYEpKFnY3Lxu02dIBcwQRT3Q5mfO4obng==
"@next/swc-linux-x64-musl@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.0.tgz#a4f39cfeb19123196a2ebc2061e60897b29ffa3f"
integrity sha512-7Y0XMUzWDWI94pxC0xWGMWrgTFKHu/myc+GTNVEwvLtI9WA0brKqZrL1tCQW/+t6J+5XqS7w+AHbViaF+muu1A==
"@next/swc-win32-arm64-msvc@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.5.tgz#1ef6d453b021b26ed2d0e317c1cb658eb57d66c2"
integrity sha512-uzsvkQY+K3EbL+97IUHPWZPwjsCmCkdH/O5Cf9wCnh0k0gaj7ob1mGKqr1vNNak+9U7HloGwuHcXnZpijWSP7w==
"@next/swc-win32-arm64-msvc@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.0.tgz#d21ef0d0c2757cee9b1d723aafb9e02ca25852eb"
integrity sha512-NM5h2gEMe8EtvOeRU3vRM83tq1xo6Qvhuz0xJem/176SAMxbqzAz4LLP3l9VyUI3SIzGyiztvF/1c0jqeq7UEA==
"@next/swc-win32-ia32-msvc@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.5.tgz#a708ed168a5d83b28519b4fcba396ab329c1a2b0"
integrity sha512-v0NaC1w8mPf620GlJaHBdEm3dm4G4AEQMasDqjzQvo0yCRrvtvzMgCIe8MocBxFHzaF6868NybMqvumxP5YxEg==
"@next/swc-win32-ia32-msvc@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.0.tgz#529852721e3f00afb9385640cbac1a899342c6ba"
integrity sha512-G7YEJZX9wkcUaBOvXQSCF9Wb2sqP8hhsmFXF6po7M3llw4b+2ut2DXLf+UMdthOdUK0u+Ijhy5F7SbW9HOn2ig==
"@next/swc-win32-x64-msvc@13.1.5":
version "13.1.5"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.5.tgz#8c7bef3dc41e624050eecb336cbd944a91fa7198"
integrity sha512-IZHwvd649ccbWyLCfu92IXEpR250NpmBkaRelPV+WVm4jrd62FKRFCNdqdCXq6TrEg9wN8cK4YG8tm44uEZqLA==
"@next/swc-win32-x64-msvc@13.2.0":
version "13.2.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.0.tgz#49bc50b1865d20b29892a415fcbaab84217112a5"
integrity sha512-QTAjSuPevnZnlHfC4600+4NvxRuPar6tWdYbPum9vnk3OIH1xu9YLK+2ArPGFd0bB2K8AoY2SIMbs1dhK0GjQQ==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@@ -745,6 +745,11 @@
"@types/express-serve-static-core" "*"
"@types/serve-static" "*"
"@types/feather-icons@^4.29.1":
version "4.29.1"
resolved "https://registry.yarnpkg.com/@types/feather-icons/-/feather-icons-4.29.1.tgz#6feec838a628fe3cf93582b71f4809e9753c38f7"
integrity sha512-8+PdenCN8UWTfyIHNaJdmk/oPg6zyw7S9kHtT8PdkmHEwfTHSrSWEHpNZJzbuWmZBXQKA/+dLVXjrloX9XixPg==
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@@ -765,16 +770,11 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
"@types/node@*", "@types/node@18.14.1", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
version "18.14.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.1.tgz#90dad8476f1e42797c49d6f8b69aaf9f876fc69f"
integrity sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ==
"@types/node@18.11.18":
version "18.11.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@@ -795,14 +795,14 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
"@types/react-dom@18.0.10":
version "18.0.10"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.10.tgz#3b66dec56aa0f16a6cc26da9e9ca96c35c0b4352"
integrity sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==
"@types/react-dom@18.0.11":
version "18.0.11"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.11.tgz#321351c1459bc9ca3d216aefc8a167beec334e33"
integrity sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==
dependencies:
"@types/react" "*"
"@types/react@*":
"@types/react@*", "@types/react@18.0.28":
version "18.0.28"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.28.tgz#accaeb8b86f4908057ad629a26635fe641480065"
integrity sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==
@@ -811,15 +811,6 @@
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/react@18.0.27":
version "18.0.27"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.27.tgz#d9425abe187a00f8a5ec182b010d4fd9da703b71"
integrity sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
@@ -1064,6 +1055,11 @@ atomic-sleep@^1.0.0:
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==
attr-accept@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b"
integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==
autoprefixer@^10.4.13:
version "10.4.13"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8"
@@ -1255,7 +1251,7 @@ chokidar@^3.5.3:
optionalDependencies:
fsevents "~2.3.2"
classnames@^2.3.2:
classnames@^2.2.5, classnames@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
@@ -1356,6 +1352,11 @@ cookie@0.5.0:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
core-js@^3.1.3:
version "3.28.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.28.0.tgz#ed8b9e99c273879fdfff0edfc77ee709a5800e4a"
integrity sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==
cors@^2.8.5:
version "2.8.5"
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
@@ -2052,6 +2053,14 @@ faye-websocket@0.11.4:
dependencies:
websocket-driver ">=0.5.1"
feather-icons@^4.29.0:
version "4.29.0"
resolved "https://registry.yarnpkg.com/feather-icons/-/feather-icons-4.29.0.tgz#4e40e3cbb7bf359ffbbf700edbebdde4e4a74ab6"
integrity sha512-Y7VqN9FYb8KdaSF0qD1081HCkm0v4Eq/fpfQYQnubpqi0hXx14k+gF9iqtRys1SIcTEi97xDi/fmsPFZ8xo0GQ==
dependencies:
classnames "^2.2.5"
core-js "^3.1.3"
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -2059,6 +2068,13 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
file-selector@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc"
integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==
dependencies:
tslib "^2.4.0"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@@ -2389,10 +2405,10 @@ googleapis-common@^6.0.0:
url-template "^2.0.8"
uuid "^9.0.0"
googleapis@105:
version "105.0.0"
resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-105.0.0.tgz#65ff8969cf837a08ee127ae56468ac3d96ddc9d5"
integrity sha512-wH/jU/6QpqwsjTKj4vfKZz97ne7xT7BBbKwzQEwnbsG8iH9Seyw19P+AuLJcxNNrmgblwLqfr3LORg4Okat1BQ==
googleapis@111.0.0:
version "111.0.0"
resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-111.0.0.tgz#aa3daac5ab033085d25fe8c52527ff35b2f7f688"
integrity sha512-nIIH+J/o/xjIscJcv3H3BCYgsFiI5ziM3Nbh2lHOWglYGqXE0Nqdt2lfCt4hX257QHEyC1y1iODDkmAMPWDYlw==
dependencies:
google-auth-library "^8.0.2"
googleapis-common "^6.0.0"
@@ -3070,30 +3086,30 @@ next-seo@^5.15.0:
resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-5.15.0.tgz#b1a90508599774982909ea44803323c6fb7b50f4"
integrity sha512-LGbcY91yDKGMb7YI+28n3g+RuChUkt6pXNpa8FkfKkEmNiJkeRDEXTnnjVtwT9FmMhG6NH8qwHTelGrlYm9rgg==
next@13.1.5:
version "13.1.5"
resolved "https://registry.yarnpkg.com/next/-/next-13.1.5.tgz#d0c230ccecf18414db78d180537d0474c53fdf73"
integrity sha512-rmpYZFCxxWAi2nJCT9sSqMLGC3cu+Pf689hx9clcyP0KbVIhh/7Dus5QcKrVd/PrAd6AjsuogSRR1mCP7BoYRw==
next@13.2.0:
version "13.2.0"
resolved "https://registry.yarnpkg.com/next/-/next-13.2.0.tgz#100b2d1dca120a3460c767ccdad80fc8e2463e31"
integrity sha512-vhByvKHedsaMwNTwXKzK4IMmNp7XI7vN4etcGUoIpLrIuDfoYA3bS0ImS4X9F6lKzopG5aVp7a1CjuzF2NGkvA==
dependencies:
"@next/env" "13.1.5"
"@next/env" "13.2.0"
"@swc/helpers" "0.4.14"
caniuse-lite "^1.0.30001406"
postcss "8.4.14"
styled-jsx "5.1.1"
optionalDependencies:
"@next/swc-android-arm-eabi" "13.1.5"
"@next/swc-android-arm64" "13.1.5"
"@next/swc-darwin-arm64" "13.1.5"
"@next/swc-darwin-x64" "13.1.5"
"@next/swc-freebsd-x64" "13.1.5"
"@next/swc-linux-arm-gnueabihf" "13.1.5"
"@next/swc-linux-arm64-gnu" "13.1.5"
"@next/swc-linux-arm64-musl" "13.1.5"
"@next/swc-linux-x64-gnu" "13.1.5"
"@next/swc-linux-x64-musl" "13.1.5"
"@next/swc-win32-arm64-msvc" "13.1.5"
"@next/swc-win32-ia32-msvc" "13.1.5"
"@next/swc-win32-x64-msvc" "13.1.5"
"@next/swc-android-arm-eabi" "13.2.0"
"@next/swc-android-arm64" "13.2.0"
"@next/swc-darwin-arm64" "13.2.0"
"@next/swc-darwin-x64" "13.2.0"
"@next/swc-freebsd-x64" "13.2.0"
"@next/swc-linux-arm-gnueabihf" "13.2.0"
"@next/swc-linux-arm64-gnu" "13.2.0"
"@next/swc-linux-arm64-musl" "13.2.0"
"@next/swc-linux-x64-gnu" "13.2.0"
"@next/swc-linux-x64-musl" "13.2.0"
"@next/swc-win32-arm64-msvc" "13.2.0"
"@next/swc-win32-ia32-msvc" "13.2.0"
"@next/swc-win32-x64-msvc" "13.2.0"
node-fetch@2.6.7:
version "2.6.7"
@@ -3668,6 +3684,15 @@ react-dom@18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react-dropzone@^14.2.3:
version "14.2.3"
resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.2.3.tgz#0acab68308fda2d54d1273a1e626264e13d4e84b"
integrity sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==
dependencies:
attr-accept "^2.2.2"
file-selector "^0.6.0"
prop-types "^15.8.1"
react-feather@^2.0.10:
version "2.0.10"
resolved "https://registry.yarnpkg.com/react-feather/-/react-feather-2.0.10.tgz#0e9abf05a66754f7b7bb71757ac4da7fb6be3b68"
@@ -4155,6 +4180,11 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
theme-change@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/theme-change/-/theme-change-2.3.0.tgz#9fec33d44c514253a0b0e9a65df4bcfa8bf9f741"
integrity sha512-MOv3g4dQfte9Q7WZKyLRshcw9JqcJCwB+CO1OS7lN1WMJcQyPzmpgwm5Ve55vQ4qt62g++A9+8s1x+vRPpm42w==
thread-stream@^0.15.1:
version "0.15.2"
resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.15.2.tgz#fb95ad87d2f1e28f07116eb23d85aba3bc0425f4"