Add notification options

This commit is contained in:
Fergal Moran
2023-03-06 05:23:19 +00:00
parent 20b1e92643
commit 144192e249
31 changed files with 806 additions and 594 deletions

View File

@@ -14,9 +14,9 @@
"dependencies": {
"@babel/plugin-transform-react-display-name": "^7.18.6",
"@headlessui/react": "^1.7.11",
"@next/font": "13.2.0",
"@next/font": "13.2.3",
"@types/feather-icons": "^4.29.1",
"@types/node": "18.14.2",
"@types/node": "18.14.6",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"@typescript-eslint/eslint-plugin": "^5.54.0",
@@ -64,7 +64,7 @@
"@hookform/devtools": "^4.3.0",
"autoprefixer": "^10.4.13",
"eslint-config-prettier": "^8.6.0",
"googleapis": "111.0.0",
"googleapis": "112.0.0",
"postcss": "^8.4.21",
"prettier": "^2.8.4",
"prettier-plugin-tailwindcss": "^0.2.2",

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 KiB

View File

@@ -12,6 +12,7 @@ import OtherwayAppProvider from "@/components/providers/OtherwayAppProvider";
import { ThemeProvider } from "@/components/providers";
import { FirebaseAppProvider } from "reactfire";
import { Theme } from "react-daisyui";
import AuthProfileProvider from "@/lib/auth/AuthProfileProvider";
// only initialize when in the browser
const font = Raleway({
@@ -35,15 +36,17 @@ const RootLayout = ({ children }: React.PropsWithChildren) => {
<ThemeProvider>
<FirebaseAppProvider firebaseConfig={firebaseConfig}>
<OtherwayAppProvider>
<Toaster />
<PushNotificationWrapper>
<div className="flex min-h-screen flex-col bg-base-100">
<NavBar />
<div className="grow place-items-center items-end bg-base-200 text-base-content">
<main className=" text-base-content">{children}</main>
<AuthProfileProvider>
<Toaster />
<PushNotificationWrapper>
<div className="flex min-h-screen flex-col bg-base-100">
<NavBar />
<div className="grow place-items-center items-end bg-base-200 text-base-content">
<main className=" text-base-content">{children}</main>
</div>
</div>
</div>
</PushNotificationWrapper>
</PushNotificationWrapper>
</AuthProfileProvider>
</OtherwayAppProvider>
</FirebaseAppProvider>
</ThemeProvider>

View File

@@ -1,32 +1,10 @@
import React from "react";
import { useState } from "react";
const LogRocket = require("logrocket");
import packageJson from "../../package.json";
const Loading = () => {
if (process.env.LOGROCKET_ID && window !== undefined) {
LogRocket.init(process.env.LOGROCKET_ID, {
release: packageJson.version,
rootHostname: "radio-otherway.fergl.ie",
console: {
shouldAggregateConsoleErrors: true,
},
network: {
requestSanitizer: (request: any) => {
// if the url contains token 'ignore' it
if (request.url.toLowerCase().indexOf("token") !== -1) {
// ignore the request response pair
return null;
}
// remove Authorization header from logrocket
request.headers.Authorization = undefined;
// otherwise log the request normally
return request;
},
},
});
}
return (
<div role="status">
<svg

View File

@@ -3,6 +3,7 @@ import React from "react";
import { useRouter } from "next/navigation";
import { IoLogoFacebook, IoLogoGoogle, IoLogoTwitter } from "react-icons/io";
import useFirebaseAuth from "@/lib/auth/signin";
import { FacebookButton, GoogleButton, TwitterButton } from "@/components/widgets/buttons/social";
const LoginPage = () => {
const router = useRouter();
@@ -15,7 +16,7 @@ const LoginPage = () => {
signInWithTwitter,
signInWithFacebook,
signIn,
getUserProfile,
getUserProfile
} = useFirebaseAuth();
const login = async (
event: React.SyntheticEvent<HTMLButtonElement>
@@ -25,7 +26,7 @@ const LoginPage = () => {
return (
<div className="font-body max-w-lg rounded-md bg-base-100 p-10 text-base-content shadow-md md:flex-1">
<h3 className="font-title my-4 text-2xl font-semibold">Account Login</h3>
<form action="#" className="flex flex-col space-y-5">
<div className="flex flex-col space-y-5">
<div className="flex flex-col space-y-1">
<label htmlFor="email" className="text-sm">
Email address
@@ -83,42 +84,9 @@ const LoginPage = () => {
<span className="h-px w-14 bg-gray-400" />
</span>
<div className="flex items-center justify-center gap-4">
<button
type="button"
className="btn w-1/3 gap-2"
onClick={signInWithTwitter}
>
<div className="text-base-content">
<IoLogoTwitter />
</div>
<span className="text-sm font-medium text-base-content">
Twitter
</span>
</button>
<button
type="button"
className="btn w-1/3 gap-2"
onClick={signInWithGoogle}
>
<div className="text-base-content">
<IoLogoGoogle />
</div>
<span className="text-sm font-medium text-base-content">
Gmail
</span>
</button>
<button
type="button"
className="btn w-1/3 gap-2"
onClick={signInWithFacebook}
>
<div className="text-base-content">
<IoLogoFacebook />
</div>
<span className="text-sm font-medium text-base-content">
Facebook
</span>
</button>
<TwitterButton onClick={signInWithTwitter} />
<GoogleButton onClick={signInWithGoogle} />
<FacebookButton onClick={signInWithFacebook} />
</div>
{error && (
<div className="alert alert-error shadow-lg">
@@ -141,7 +109,7 @@ const LoginPage = () => {
</div>
)}
</div>
</form>
</div>
</div>
);
};

View File

@@ -9,10 +9,11 @@ import UpcomingShowsTable from "./UpcomingShowsTable";
interface IHomePageComponentProps {
shows: Show[] | undefined;
}
const HomePageComponent = ({ shows }: IHomePageComponentProps) => {
const _getLayout = () => {
if (!shows) {
return <Loading />;
return <div className="p-4"><Loading /></div>;
}
if (shows.length === 0) {
return <NoShows />;

View File

@@ -1,41 +1,47 @@
import React from "react";
import { RemindMeButton } from "@/components/widgets";
import { getMonthName, getTime } from "@/lib/util/dateUtils";
import Image from "next/image";
import { Show } from "@/models";
interface IUpcomingShowsTableProps {
shows: Show[];
}
const UpcomingShowsTable = ({ shows }: IUpcomingShowsTableProps) => {
return (
<table className="table w-full">
{/* head */}
<thead>
<tr>
<th>Who?</th>
<th>When?</th>
<th>What?</th>
<th></th>
</tr>
<tr>
<th></th>
<th>Who?</th>
<th>When?</th>
<th>What?</th>
<th></th>
</tr>
</thead>
<tbody>
{/* row 1 */}
{shows &&
shows.map((show: Show) => (
<tr key={show.id}>
<th>{show.creator}</th>
<td className="pl-5 pr-3 whitespace-no-wrap">
<div className="text-gray-400">
{`${new Date(show.date).getDay()} ${getMonthName(show.date)}`}{" "}
@ {getTime(show.date)}
</div>
</td>
<td>{show.title}</td>
<th>
<RemindMeButton showId={show.id} />
</th>
</tr>
))}
{/* row 1 */}
{shows &&
shows.map((show: Show) => (
<tr key={show.id}>
<th>
<Image alt="Show" src={show.image ? show.image : "/img/default-show.png"} width={48} height={48} />
</th>
<th>{show.creator}</th>
<td className="pl-5 pr-3 whitespace-no-wrap">
<div className="text-gray-400">
{`${new Date(show.date).getDay()} ${getMonthName(show.date)}`}{" "}
@ {getTime(show.date)}
</div>
</td>
<td>{show.title}</td>
<th>
<RemindMeButton showId={show.id} />
</th>
</tr>
))}
</tbody>
</table>
);

View File

@@ -1,15 +1,18 @@
"use client";
import React, { useEffect, useMemo } from "react";
import React, { useContext, useEffect, useMemo } from "react";
import { useRouter } from "next/navigation";
import { User, Bell } from "react-feather";
import classNames from "classnames";
import ProfilePageComponentProfile from "./ProfilePageComponentProfile";
import ProfilePageComponentNotifications from "./ProfilePageComponentNotifications";
import { SubmitHandler, useForm } from "react-hook-form";
import { doc, setDoc } from "firebase/firestore";
import ToastService from "@/components/widgets/toast";
import logger from "@/lib/util/logging";
import { removeUndefinedProperties } from "@/lib/util/objectUtils";
import { AuthProfileContext } from "@/lib/auth/AuthProfileProvider";
import { useUser } from "reactfire";
import Loading from "@/app/loading";
import { Users } from "@/lib/db/collections";
export type ProfileForm = {
displayName: string;
@@ -18,155 +21,145 @@ export type ProfileForm = {
photoURL: string;
headerPhotoURL: string;
mobileNumber: string;
notificationsBrowser: boolean;
notificationsMobile: boolean;
notificationsWhatsapp: boolean;
notificationsEmail: boolean;
};
import { useUser } from "reactfire";
const ProfilePageComponent = () => {
return <div>Profile</div>;
// const { status, data: profile } = useUser();
// const router = useRouter();
// React.useEffect(() => {
// if (status !== "loading" && !profile) {
// router.push("/");
// }
// }, [status, profile, router]);
const { profile } = useContext(AuthProfileContext);
const { status, data: user } = useUser();
const router = useRouter();
const subNavigation = [
{ name: "profile", title: "Profile", icon: User },
{
name: "notifications",
title: "Notifications",
icon: Bell
}
];
// const subNavigation = [
// { name: "profile", title: "Profile", icon: User },
// {
// name: "notifications",
// title: "Notifications",
// icon: Bell,
// },
// ];
// const [selectedItem, setSelectedItem] = React.useState("profile");
// const {
// register,
// handleSubmit,
// setValue,
// reset,
// watch,
// control,
// formState: { errors },
// } = useForm<ProfileForm>({
// defaultValues: useMemo(() => {
// return profile;
// }, [profile]),
// });
const [selectedItem, setSelectedItem] = React.useState("profile");
const {
register,
handleSubmit,
setValue,
reset,
watch,
control,
formState: { errors }
} = useForm<ProfileForm>({
defaultValues: useMemo(() => {
return profile;
}, [profile])
});
// useEffect(() => {
// if (profile) {
// reset(profile);
// }
// }, [profile, reset]);
// const onSubmit: SubmitHandler<ProfileForm> = async (data) => {
// console.log(data);
// try {
// const newProfile = removeUndefinedProperties({
// displayName: data.displayName,
// email: data.email,
// about: data.about,
// photoURL: data.photoURL,
// headerPhotoURL: data.headerPhotoURL,
// mobileNumber: data.mobileNumber,
// lastSeen: new Date(),
// });
// const result = await setDoc(
// doc(users, profile?.id),
// Object.assign({}, newProfile),
// {
// merge: true,
// }
// );
// console.log("ProfilePageComponentProfile", "_submitProfileForm", result);
// ToastService.success("Successfully updated your profile", "Success");
// } catch (err) {
// logger.error("ProfilePageComponentProfile", "_submitProfileForm", err);
// ToastService.error("Failed to update your profile.");
// }
// };
useEffect(() => {
if (profile) {
console.log("ProfilePageComponent", "profileChanged", profile);
reset(profile);
}
}, [profile, reset]);
const onSubmit: SubmitHandler<ProfileForm> = async (data) => {
console.log(data);
try {
const newProfile = removeUndefinedProperties({
displayName: data.displayName,
email: data.email,
about: data.about,
photoURL: data.photoURL,
headerPhotoURL: data.headerPhotoURL,
mobileNumber: data.mobileNumber,
lastSeen: new Date(),
notificationsEmail: data.notificationsEmail,
notificationsMobile: data.notificationsMobile,
notificationsWhatsapp: data.notificationsWhatsapp,
notificationsBrowser: data.notificationsBrowser
});
console.log("ProfilePageComponent", "Updating profile", newProfile);
if (profile?.id) {
const result = await Users.set(profile.id, newProfile);
}
ToastService.success("Successfully updated your profile", "Success");
} catch (err) {
logger.error("ProfilePageComponentProfile", "_submitProfileForm", err);
ToastService.error("Failed to update your profile.");
}
};
// useEffect(() => {}, [selectedItem]);
// const _getView = () => {
// if (status === "loading") {
// return <div>Loading</div>;
// } else if (status === "success" && !profile) {
// return <div>Rerouting</div>;
// } else if (status === "success" && profile) {
// return (
// <div className="pt-4 overflow-hidden">
// <div className="justify-center flex-1 px-2 mx-2 md:flex md:justify-start">
// <span className="text-2xl font-bold">Your Profile</span>
// </div>
// <div className="mt-1 divider" />
// <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}
// >
// <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"
// />
// <span className="truncate">{item.title}</span>
// </a>
// ))}
// </nav>
// </aside>
useEffect(() => {
}, [selectedItem]);
const _getView = () => {
// <div className="p-4 divide-y lg:col-span-9">
// <form onSubmit={handleSubmit(onSubmit)}>
// {selectedItem === "profile" ? (
// <ProfilePageComponentProfile
// setValue={setValue}
// register={register}
// profile={profile}
// />
// ) : (
// <ProfilePageComponentNotifications
// register={register}
// control={control}
// profile={profile}
// />
// )}
// <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>
// </div>
// </div>
// </div>
// );
// } else {
// return (
// <div>
// <h1>This is weird</h1>
// </div>
// );
// }
// };
// return _getView();
return profile ? (
<div className="pt-4 overflow-hidden">
<div className="justify-center flex-1 px-2 mx-2 md:flex md:justify-start">
<span className="text-2xl font-bold">Your Profile</span>
</div>
<div className="mt-1 divider" />
<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}
>
<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"
/>
<span className="truncate">{item.title}</span>
</a>
))}
</nav>
</aside>
<div className="p-4 divide-y lg:col-span-9">
<form onSubmit={handleSubmit(onSubmit)}>
{selectedItem === "profile" ? (
<ProfilePageComponentProfile
setValue={setValue}
register={register}
profile={profile}
/>
) : (
<ProfilePageComponentNotifications
register={register}
control={control}
profile={profile}
/>
)}
<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>
</div>
</div>
</div>
) : <Loading />;
};
return _getView();
};
export default ProfilePageComponent;

View File

@@ -2,7 +2,7 @@ import React from "react";
import { HeadingSubComponent } from "@/components/widgets/text";
import {
PhoneNumber,
RequestPushNotifications,
RequestPushNotifications
} from "@/components/widgets/notifications";
import { UseFormRegister } from "react-hook-form";
import { ProfileForm } from "@/components/pages/profile/ProfilePageComponent";
@@ -13,11 +13,12 @@ interface IProfilePageComponentNotificationsProps {
control: any;
profile: Profile;
}
const ProfilePageComponentNotifications = ({
register,
control,
profile,
}: IProfilePageComponentNotificationsProps) => {
register,
control,
profile
}: IProfilePageComponentNotificationsProps) => {
const [notificationPermissionsGranted, setNotificationPermissionsGranted] =
React.useState(Notification.permission !== "granted");
@@ -61,6 +62,44 @@ const ProfilePageComponentNotifications = ({
</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="Notification methods"
subHeading="Where you'd like to see notifications when a show is starting"
/>
<div className="mt-1 sm:col-span-2 sm:mt-0">
<div className="flex flex-grow max-w-lg rounded-md shadow-sm">
<div className="form-control">
<label className="cursor-pointer label">
<span className="label-text mr-2">Browser</span>
<input type="checkbox" id="notificationsBrowser"
className="toggle toggle-primary" {...register("notificationsBrowser")} />
</label>
</div>
<div className="form-control">
<label className="cursor-pointer label">
<span className="label-text mr-2">Mobile</span>
<input type="checkbox" id="notificationsMobile"
className="toggle toggle-primary" {...register("notificationsMobile")} />
</label>
</div>
<div className="form-control">
<label className="cursor-pointer label">
<span className="label-text mr-2">WhatsApp</span>
<input type="checkbox" id="notificationsWhatsapp"
className="toggle toggle-primary" {...register("notificationsWhatsapp")} />
</label>
</div>
<div className="form-control">
<label className="cursor-pointer label">
<span className="label-text mr-2">Email</span>
<input type="checkbox" id="notificationsEmail"
className="toggle toggle-primary" {...register("notificationsEmail")} />
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -12,11 +12,12 @@ interface IProfilePageComponentProfileProps {
register: UseFormRegister<ProfileForm>;
setValue: UseFormSetValue<ProfileForm>;
}
const ProfilePageComponentProfile = ({
profile,
register,
setValue,
}: IProfilePageComponentProfileProps) => {
profile,
register,
setValue
}: IProfilePageComponentProfileProps) => {
const [photoURLFile, setPhotoURLFile] = useState("");
return (
<div className="space-y-8 divide-y sm:space-y-5">
@@ -40,6 +41,7 @@ const ProfilePageComponentProfile = ({
id="displayName"
type="text"
label="Display name"
showLabel={false}
{...register("displayName")}
/>
</div>

View File

@@ -1,16 +1,47 @@
import React from "react";
import { AuthProvider, FirestoreProvider, useFirebaseApp } from "reactfire";
import React, { useEffect } from "react";
import { AuthProvider, FirestoreProvider, StorageProvider, useFirebaseApp } from "reactfire";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import LogRocket from "logrocket";
import packageJson from "../../../package.json";
import { getStorage } from "@firebase/storage";
const OtherwayAppProvider = ({ children }: React.PropsWithChildren) => {
const app = useFirebaseApp();
const auth = getAuth(app);
const firestore = getFirestore(app);
const storage = getStorage(app);
useEffect(() => {
if (process.env.LOGROCKET_ID && window !== undefined) {
LogRocket.init(process.env.LOGROCKET_ID, {
release: packageJson.version,
rootHostname: "radio-otherway.fergl.ie",
console: {
shouldAggregateConsoleErrors: true
},
network: {
requestSanitizer: (request: any) => {
// if the url contains token 'ignore' it
if (request.url.toLowerCase().indexOf("token") !== -1) {
// ignore the request response pair
return null;
}
// remove Authorization header from logrocket
request.headers.Authorization = undefined;
// otherwise log the request normally
return request;
}
}
});
}
}, []);
return (
<AuthProvider sdk={auth}>
<FirestoreProvider sdk={firestore}>{children}</FirestoreProvider>
<FirestoreProvider sdk={firestore}>
<StorageProvider sdk={storage}>
{children}
</StorageProvider>
</FirestoreProvider>
</AuthProvider>
);
};

View File

@@ -0,0 +1,15 @@
import React from "react";
import { IoLogoFacebook } from "react-icons/io";
interface IBaseSocialButtonProps extends React.PropsWithChildren {
onClick: ($event: any) => {};
}
const BaseSocialButton = ({ onClick, children }: IBaseSocialButtonProps) => {
return <button className="btn" onClick={onClick}>
{children}
</button>;
};
export default BaseSocialButton;

View File

@@ -0,0 +1,15 @@
import React from "react";
import { IoLogoFacebook } from "react-icons/io";
import BaseSocialButton from "@/components/widgets/buttons/social/BaseSocialButton";
import { ISocialButtonProps } from "@/components/widgets/buttons/social/socialButtonProps";
const FacebookButton = ({ onClick }: ISocialButtonProps) => {
return (
<BaseSocialButton onClick={onClick}>
<IoLogoFacebook className="mr-2" />
Facebook
</BaseSocialButton>
);
};
export default FacebookButton;

View File

@@ -0,0 +1,15 @@
import React from "react";
import { ISocialButtonProps } from "./socialButtonProps";
import { IoLogoGoogle } from "react-icons/io";
import BaseSocialButton from "@/components/widgets/buttons/social/BaseSocialButton";
const GoogleButton = ({ onClick }: ISocialButtonProps) => {
return (
<BaseSocialButton onClick={onClick}>
<IoLogoGoogle className="mr-2" />
Google
</BaseSocialButton>
);
};
export default GoogleButton;

View File

@@ -1,24 +1,14 @@
import React from "react";
import { ISocialButtonProps } from "./socialButtonProps";
import { IoLogoTwitter } from "react-icons/io";
import BaseSocialButton from "@/components/widgets/buttons/social/BaseSocialButton";
const TwitterButton = ({ onClick }: ISocialButtonProps) => {
return (
<button
type="button"
className="btn-secondary btn mb-2 flex
w-1/3 gap-2 rounded px-6 py-2.5 text-xs font-medium uppercase leading-normal text-white shadow-md transition duration-150 ease-in-out hover:shadow-lg focus:shadow-lg focus:outline-none focus:ring-0 active:shadow-lg"
style={{ backgroundColor: "#1da1f2" }}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="mr-2 h-3.5 w-3.5"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z" />
</svg>
<BaseSocialButton onClick={onClick}>
<IoLogoTwitter className="mr-2" />
Twitter
</button>
</BaseSocialButton>
);
};

View File

@@ -1,3 +1,5 @@
import TwitterButton from "./TwitterButton";
import FacebookButton from "./FacebookButton";
import GoogleButton from "./GoogleButton";
export { TwitterButton };
export { TwitterButton, FacebookButton, GoogleButton };

View File

@@ -1,3 +1,3 @@
export interface ISocialButtonProps {
onClick: () => {};
onClick: ($event: any) => {};
}

View File

@@ -2,7 +2,7 @@ import React from "react";
import {
ref as storageRef,
uploadBytesResumable,
getDownloadURL,
getDownloadURL
} from "firebase/storage";
import Image from "next/image";
import {
@@ -10,8 +10,9 @@ import {
useRef,
useState,
forwardRef,
ChangeEventHandler,
ChangeEventHandler
} from "react";
const path = require("path");
import { UploadCloud } from "react-feather";
import { getFileExtension } from "@/lib/util/fileUtils";
@@ -20,7 +21,7 @@ import {
Controller,
FieldPath,
UseFormReturn,
UseFormSetValue,
UseFormSetValue
} from "react-hook-form";
import { ProfileForm } from "@/components/pages/profile/ProfilePageComponent";
import { useStorage } from "reactfire";
@@ -49,7 +50,7 @@ const FirebaseImageUploader = forwardRef<
imageUrl,
setValue,
onChange,
onBlur,
onBlur
},
ref
) => {
@@ -140,7 +141,7 @@ const FirebaseImageUploader = forwardRef<
isUploading,
itemId,
setValue,
storage,
storage
]);
return imageType === "avatar" ? (
@@ -151,7 +152,7 @@ const FirebaseImageUploader = forwardRef<
<Image
alt="Existing image"
src={imageUrl}
className="w-full h-full "
className="w-full h-full"
width={48}
height={48}
/>
@@ -161,7 +162,8 @@ const FirebaseImageUploader = forwardRef<
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" />
<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>

View File

@@ -15,6 +15,7 @@ const InputText = forwardRef<HTMLInputElement, ITextInputProps>(
)}
<input
id={id}
name={id}
className="w-full input-bordered input"
type={type || "text"}
placeholder={placeholder || ""}

View File

@@ -0,0 +1,44 @@
import React, { createContext, useEffect, useReducer, useState } from "react";
import { Profile } from "@/models";
import { useUser } from "reactfire";
import useFirebaseAuth from "@/lib/auth/signin";
import logger from "@/lib/util/logging";
interface IAuthProfileProviderState {
profile: Profile | undefined;
setProfile: (profile: Profile | undefined) => void;
}
const initialState: IAuthProfileProviderState = {
profile: undefined,
setProfile: profile => {
}
};
export const AuthProfileContext = createContext(initialState);
const AuthProfileProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
const { status, data: user } = useUser();
const { getUserProfile } = useFirebaseAuth();
useEffect(() => {
console.log("AuthProfileProvider", "statusChanged", status);
if (status === "success" && user) {
const profile = getUserProfile()
.then(profile => {
if (profile) {
setProfile(profile);
}
}).catch(err => {
logger.debug("AuthProfileProvider", "Error loading provider", err);
});
}
}, [status, user]);
const [profile, setProfile] = useState<Profile>();
return <AuthProfileContext.Provider value={{ profile, setProfile }}>
{children}
</AuthProfileContext.Provider>;
};
;
export default AuthProfileProvider;

View File

@@ -12,20 +12,20 @@ import {
signInWithPopup,
signOut,
TwitterAuthProvider,
UserCredential,
UserCredential
} from "firebase/auth";
import { getDoc, doc, setDoc } from "firebase/firestore";
import { clear } from "localforage";
import router from "next/router";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useContext, useEffect, useState } from "react";
import { Users } from "../db/collections";
import logger from "../util/logging";
import { useRouter } from "next/navigation";
import { AuthProfileContext } from "@/lib/auth/AuthProfileProvider";
const useFirebaseAuth = () => {
const router = useRouter();
const auth = getAuth();
const [errorCredential, setErrorCredential] =
useState<OAuthCredential | null>();
const [profile, setProfile] = useState<Profile | undefined>();
const [loading, setLoading] = useState(true);
const _processSignIn = async (
provider: any
@@ -59,7 +59,6 @@ const useFirebaseAuth = () => {
};
const clear = () => {
setProfile(undefined);
setLoading(true);
};
const getUserProfile = useCallback(async () => {
@@ -69,31 +68,22 @@ const useFirebaseAuth = () => {
const savedProfile = await Users.get(auth.currentUser.uid);
const profile: Profile = new Profile(
auth.currentUser.uid,
(savedProfile.email || auth.currentUser.email) as string,
(savedProfile.displayName || auth.currentUser.displayName) as string,
(savedProfile.photoURL || auth.currentUser.photoURL) as string,
savedProfile.about as string,
savedProfile.mobileNumber as string,
(savedProfile?.email || auth.currentUser.email) as string,
(savedProfile?.displayName || auth.currentUser.displayName) as string,
(savedProfile?.photoURL || auth.currentUser.photoURL) as string,
savedProfile?.about as string,
savedProfile?.mobileNumber as string,
new Date(),
savedProfile.deviceRegistrations
savedProfile?.notificationsBrowser,
savedProfile?.notificationsMobile,
savedProfile?.notificationsWhatsapp,
savedProfile?.notificationsEmail,
savedProfile?.deviceRegistrations
);
setProfile(profile);
await Users.set(auth.currentUser.uid, Object.assign({}, profile));
return profile;
}
}, [auth.currentUser]);
const authStateChanged = useCallback(
async (user: any) => {
if (user) {
setLoading(true);
const profile = await getUserProfile();
setProfile(profile);
}
setLoading(false);
},
[getUserProfile]
);
const signIn = (email: string, password: string) =>
signInWithEmailAndPassword(auth, email, password);
@@ -126,7 +116,6 @@ const useFirebaseAuth = () => {
if (result) {
const credential = GoogleAuthProvider.credentialFromResult(result);
const profile = await getUserProfile();
setProfile(profile);
router.push("/");
}
};
@@ -136,7 +125,6 @@ const useFirebaseAuth = () => {
if (result) {
const credential = TwitterAuthProvider.credentialFromResult(result);
const profile = await getUserProfile();
setProfile(profile);
router.push("/");
}
};
@@ -144,12 +132,7 @@ const useFirebaseAuth = () => {
const provider = new FacebookAuthProvider();
await _processSignIn(provider);
};
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, authStateChanged);
return unsubscribe;
}, [auth, authStateChanged]);
return {
profile,
loading,
signIn,
signUp,
@@ -158,7 +141,7 @@ const useFirebaseAuth = () => {
signInWithTwitter,
signInWithFacebook,
// linkAccounts,
getUserProfile,
getUserProfile
};
};
export default useFirebaseAuth;

View File

@@ -1,23 +1,45 @@
import { Show } from "@/models";
import { createCollection } from "..";
import { showConverter } from "../util/converters";
import { doc, getDocs, where } from "@firebase/firestore";
import { doc, getDocs, setDoc, where } from "@firebase/firestore";
import { getDoc, query } from "firebase/firestore";
import { Users } from "@/lib/db/collections/index";
const Shows = {
collection: createCollection<Show>("shows").withConverter(showConverter),
getShowById: async (showId: string) => {
const q = await getDoc(doc(Shows.collection, showId));
return Show.fromJson(q.data());
},
collection: createCollection<Show>("shows").withConverter(showConverter),
getUpcomingShows: async (): Promise<Show[]> => {
const upcomingShows = await getDocs(
query(Shows.collection, where("date", ">", new Date()))
);
return upcomingShows.docs.map((s) => Show.fromJson(s.data()));
wrapShow: async (show: Show): Promise<Show> => {
const user = await Users.getByEmail(show.creator);
if (user && user.displayName) {
show.creator = user.displayName;
show.image = user.photoURL;
}
return show;
},
set: async (showId: string, show: Show) => {
const showRef = doc(Shows.collection, showId);
await setDoc(
showRef,
show,
{ merge: true }
);
},
get: async (showId: string) => {
const q = await getDoc(doc(Shows.collection, showId));
return Show.fromJson(q.data());
},
getUpcomingShows: async (): Promise<Show[]> => {
const upcomingShows = await getDocs(
query(Shows.collection, where("date", ">", new Date()))
);
return upcomingShows.docs.map((s) => {
const show = s.data();
console.log("Shows", "mapping upcoming shows", show);
return Show.fromJson(show);
}
);
}
}
};
;
export default Shows;

View File

@@ -1,20 +1,34 @@
import { Profile } from "@/models";
import { doc, setDoc } from "@firebase/firestore";
import { getDoc } from "firebase/firestore";
import { doc, getDocs, setDoc, where } from "@firebase/firestore";
import { getDoc, query } from "firebase/firestore";
import { createCollection } from "..";
const Users = {
collection: createCollection<Profile>("users"),
get: async (id: string) => {
get: async (id: string): Promise<Profile> => {
const result = await getDoc(doc(Users.collection, id));
return result.data();
return Profile.fromJson(result.data());
},
getByEmail: async (email: string): Promise<Profile | undefined> => {
const userQuery = await getDocs(query(Users.collection, where("email", "==", email)));
if (userQuery.docs.length > 0) {
const data = userQuery.docs[0].data();
return Profile.fromJson(data);
}
throw Error("Unable to find user");
},
getNotifiable: async (): Promise<Profile[] | undefined> => {
const usersQuery = await getDocs(
query(Users.collection, where("mobileNumber", "!=", null))
);
return usersQuery.docs.map(r => Profile.fromJson(r.data()));
},
set: async (id: string, user: Profile) => {
await setDoc(doc(Users.collection, id), user, {
merge: true,
merge: true
});
},
}
};
export default Users;

View File

@@ -3,34 +3,18 @@ import {
DocumentData,
collection,
CollectionReference,
initializeFirestore,
getFirestore,
getFirestore
} from "firebase/firestore";
const firebaseConfig = {
apiKey: "AIzaSyDtk_Ym-AZroXsHvQVcdHXYyc_TvgycAWw",
authDomain: "radio-otherway.firebaseapp.com",
projectId: "radio-otherway",
storageBucket: "radio-otherway.appspot.com",
messagingSenderId: "47147490249",
appId: "1:47147490249:web:6243de17f52ef79126e618",
measurementId: "G-X3MXP6RMMC",
// apiKey: process.env.API_KEY,
// authDomain: process.env.AUTH_DOMAIN,
// projectId: process.env.PROJECT_ID,
// storageBucket: process.env.STORAGE_BUCKET,
// // messagingSenderId: process.env.STORAGE_BUCKET,
// appId: process.env.APP_ID,
// measurementId: process.env.MEASUREMENT_ID,
apiKey: process.env.NEXT_PUBLIC_API_KEY,
authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_APP_ID,
measurementId: process.env.NEXT_PUBLIC_MEASUREMENT_ID
};
const firebaseApp = initializeApp(firebaseConfig);
const firestore = getFirestore(firebaseApp);

View File

@@ -11,6 +11,10 @@ export default class Profile {
mobileNumber?: string;
lastSeen: Date;
deviceRegistrations?: DeviceRegistration[] = [];
notificationsBrowser: boolean;
notificationsMobile: boolean;
notificationsWhatsapp: boolean;
notificationsEmail: boolean;
constructor(
id: string,
@@ -20,6 +24,10 @@ export default class Profile {
about?: string,
mobileNumber?: string,
lastSeen?: Date,
notificationsBrowser?: boolean,
notificationsMobile?: boolean,
notificationsWhatsapp?: boolean,
notificationsEmail?: boolean,
deviceRegistrations?: DeviceRegistration[]
) {
this.id = id;
@@ -28,8 +36,33 @@ export default class Profile {
this.photoURL = photoURL;
this.about = about || "";
this.mobileNumber = mobileNumber || "";
this.notificationsBrowser = notificationsBrowser || false;
this.notificationsMobile = notificationsMobile || false;
this.notificationsWhatsapp = notificationsWhatsapp || false;
this.notificationsEmail = notificationsEmail || false;
this.lastSeen = lastSeen || new Date();
this.deviceRegistrations = deviceRegistrations || this.deviceRegistrations;
}
static fromJson(r: any): Profile {
const profile = new Profile(
r.id,
r.email,
r.displayName,
r.photoURL,
r.about,
r.mobileNumber,
r.lastSeen,
r.lastSeen
);
if (r.deviceRegistrations) {
profile.deviceRegistrations = r.deviceRegistrations;
}
profile.notificationsBrowser = r.notificationsBrowser || false;
profile.notificationsMobile = r.notificationsMobile || false;
profile.notificationsWhatsapp = r.notificationsWhatsapp || false;
profile.notificationsEmail = r.notificationsEmail || false;
return profile;
}
}

View File

@@ -3,12 +3,14 @@ export default class Show {
title: string;
date: string;
creator: string;
image?: string;
constructor(id: string, title: string, date: Date, creator: string) {
constructor(id: string, title: string, date: Date, creator: string, image?: string) {
this.id = id;
this.title = title;
this.date = date.toString();
this.creator = creator;
this.image = image;
}
static fromJson(r: any): Show {
@@ -16,6 +18,8 @@ export default class Show {
r.id,
r.title,
new Date(r.date),
r.creator);
r.creator,
r.image
);
}
}

View File

@@ -20,16 +20,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
} else {
const entries: Show[] = e?.events.map((r: any) => Show.fromJson(r));
for (const entry of entries) {
const showRef = doc(Shows.collection, entry.id);
await setDoc(
showRef,
{
title: entry.title,
date: entry.date,
creator: entry.creator,
},
{ merge: true }
);
await Shows.set(entry.id, await Shows.wrapShow(entry));
}
if (e?.syncToken) {
await Settings.write("CalendarSyncToken", e?.syncToken);

View File

@@ -1,10 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { shows, users } from "@/lib/db";
import { Show } from "@/models";
import { doc, getDocs } from "@firebase/firestore";
import { getDoc, query, where } from "firebase/firestore";
import { sendWhatsApp } from "@/lib/util/notifications/sms";
import { StatusCodes } from "http-status-codes";
import { Shows, Users } from "@/lib/db/collections";
import { sendWhatsApp } from "@/lib/util/notifications/sms";
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== "POST") {
@@ -12,27 +9,19 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}
const { showId } = req.body;
const q = await getDoc(doc(shows, showId));
const show = Show.fromJson(q.data());
const show = await Shows.get(showId);
const users = await Users.getNotifiable();
//iterate through every user and get their notifications
//and send 'em off
//TODO: Move this out of here
const usersQuery = await getDocs(
query(users, where("mobileNumber", "!=", null))
);
usersQuery.forEach(async (u) => {
const user = u.data();
users?.forEach(user => {
const message = (process.env.WHATSAPP_SHOW_HOUR as string)
.replace("{{1}}", user.displayName as string)
.replace("{{2}}", show.creator);
if (user.mobileNumber) {
console.log("notify", "sending notification to ", user);
const message = (process.env.WHATSAPP_SHOW_HOUR as string)
.replace("{{1}}", user.displayName as string)
.replace("{{2}}", show.creator);
await sendWhatsApp(user.mobileNumber, message);
sendWhatsApp(user.mobileNumber, message);
}
});
res.status(StatusCodes.OK).json({ status: "OK" });
res.end();
};

View File

@@ -1,9 +1,11 @@
import { getDoc } from "firebase/firestore";
import { StatusCodes } from "http-status-codes";
import { NextApiRequest, NextApiResponse } from "next";
import { firebaseConfig } from "@/lib/db";
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
res.status(StatusCodes.OK).json({ response: "Hello Sailor" });
res.status(StatusCodes.OK).json(firebaseConfig);
res.end();
};

View File

@@ -207,15 +207,15 @@
dependencies:
text-decoding "^1.0.0"
"@firebase/analytics-compat@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.3.tgz#ed60472dcd2bfa3f2fa7a5478b63bb7aece652ed"
integrity sha512-HmvbB4GMgh8AUlIDIo/OuFENLCGRXxMvtOueK+m8+DcfqBvG+mkii0Mi9ovo0TnMM62cy3oBYG7PHdjIQNLSLA==
"@firebase/analytics-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.4.tgz#3887676286ead7b30f9880581e0144f43bc71f16"
integrity sha512-ZN4K49QwOR8EWIUTV03VBdcVkz8sVsfJmve4g2+FEIj0kyTK0MdoVTWNOwWj9TVi2p/7FvKRKkpWxkydmi9x7g==
dependencies:
"@firebase/analytics" "0.9.3"
"@firebase/analytics" "0.9.4"
"@firebase/analytics-types" "0.8.0"
"@firebase/component" "0.6.3"
"@firebase/util" "1.9.2"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/analytics-types@0.8.0":
@@ -223,27 +223,27 @@
resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.8.0.tgz#551e744a29adbc07f557306530a2ec86add6d410"
integrity sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==
"@firebase/analytics@0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.9.3.tgz#ae653a6c6bcd667efd1d3cc5207e3e621d737028"
integrity sha512-XdYHBi6RvHYVAHGyLxXX0uRPwZmGeqw1JuWS1rMEeRF/jvbxnrL81kcFAHZVRkEvG9bXAJgL2fX9wmDo3e622w==
"@firebase/analytics@0.9.4":
version "0.9.4"
resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.9.4.tgz#1b863bd795c3dbe3d278467e8c9dd0e6c54f37a3"
integrity sha512-Mb2UaD0cyJ9DrTk4Okz8wqpjZuVRVXHZOjhbQcmGb8VtibXY1+jm/k3eJ21r7NqUKnjWejYM2EX+hI9+dtXGkQ==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/installations" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-check-compat@0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.3.3.tgz#a1d594ec722fa81f7e11977b407a187e8afdb19a"
integrity sha512-25AQ4W7WUL8OWas40GsABuNU622Dm1ojbfeZ03uKtLj5Af7FerJ25u7zkgm+11pc6rpr5v8E5oxEG9vmNRndEA==
"@firebase/app-check-compat@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.3.4.tgz#43cad88c9211a84bb98f205ba075c34acd8933c2"
integrity sha512-s6ON0ixPKe99M1DNYMI2eR5aLwQZgy0z8fuW1tnEbzg5p/N/GKFmqiIHSV4gfp8+X7Fw5NLm7qMfh4xrcPgQCw==
dependencies:
"@firebase/app-check" "0.6.3"
"@firebase/app-check" "0.6.4"
"@firebase/app-check-types" "0.5.0"
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-check-interop-types@0.2.0":
@@ -256,25 +256,25 @@
resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.5.0.tgz#1b02826213d7ce6a1cf773c329b46ea1c67064f4"
integrity sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==
"@firebase/app-check@0.6.3":
version "0.6.3"
resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.6.3.tgz#221060e5e0eac1e20ee724478b61e89ad6e8420a"
integrity sha512-T9f9ceFLs7x4D2T6whu5a6j7B3qPuYHiZHZxW6DkMh/FoMmRA4/q/HVyu01i9+LyJJx2Xdo6eCcj6ofs9YZjqA==
"@firebase/app-check@0.6.4":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.6.4.tgz#cb2f7b23f80126800a5632c1d766635266e1b2ff"
integrity sha512-M9qyVTWkEkHXmgwGtObvXQqKcOe9iKAOPqm0pCe74mzgKVTNq157ff39+fxHPb4nFbipToY+GuvtabLUzkHehQ==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-compat@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.2.3.tgz#a31c823d415c041591ee8c355776cd5bca7ef6e2"
integrity sha512-sX6rD1KFX6K2CuCnQvc9jZLOgAFZ+sv2jKKahIl4SbTM561D682B8n4Jtx/SgDrvcTVTdb05g4NhZOws9hxYxA==
"@firebase/app-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.2.4.tgz#610bf28a655373e6b4cda2115fb594f3c576d7d5"
integrity sha512-eYKtxMrzi+icZ6dFeJEoEpxu3aq1jp2PeL5vPIOAavJpdgRWFmSGmw3a46Hkay+GGGX4fkJG3vCfuoQsf5ksjA==
dependencies:
"@firebase/app" "0.9.3"
"@firebase/component" "0.6.3"
"@firebase/app" "0.9.4"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-types@0.9.0":
@@ -282,26 +282,26 @@
resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.0.tgz#35b5c568341e9e263b29b3d2ba0e9cfc9ec7f01e"
integrity sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==
"@firebase/app@0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.9.3.tgz#6a9c9b2544fa9a50ad8f405355896c54339c228b"
integrity sha512-G79JUceVDaHRZ4WkA11GyVldVXhdyRJRwWVQFFvAAVfQJLvy2TA6lQjeUn28F6FmeUWxDGwPC30bxCRWq7Op8Q==
"@firebase/app@0.9.4":
version "0.9.4"
resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.9.4.tgz#28eb5cd0406f92825afb32a53194d59c19cddb7b"
integrity sha512-xX8I6pNqUxhxhaghy9fbjOWOP9ndx5UeN5F0V/PWD2u7xRg88YkzZrDocTAIU17y82UPZ1x1E5n15CsXGcxaOg==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
idb "7.0.1"
tslib "^2.1.0"
"@firebase/auth-compat@0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.3.3.tgz#e52f654e3f14b81cecb2fe252e564778fbba0a47"
integrity sha512-9asUuGtkzUVELH3LYXdiom1nVVV9bqEPqzHohanoofHL/oVTNcHZ4AQ5CXjNATfb6c1WH32U+nEuPiYg26UUIw==
"@firebase/auth-compat@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.3.4.tgz#3c00b391876d6192e35eaf805adda3aef43199a5"
integrity sha512-AVNZ4pwLV063ngPKU+8tykQ6v+fRlKfBWEp1W+JU1pEJI+GK0thOPrCn22lWyI8LYiDrh3MLIiBJCv7fsyQajw==
dependencies:
"@firebase/auth" "0.21.3"
"@firebase/auth" "0.21.4"
"@firebase/auth-types" "0.12.0"
"@firebase/component" "0.6.3"
"@firebase/util" "1.9.2"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
tslib "^2.1.0"
@@ -315,14 +315,14 @@
resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.12.0.tgz#f28e1b68ac3b208ad02a15854c585be6da3e8e79"
integrity sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==
"@firebase/auth@0.21.3":
version "0.21.3"
resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.21.3.tgz#277a3bf4b09db1b5dd471970cecd844d1835dcbf"
integrity sha512-HPbcwgArLBVTowFcn4qaQr6LCx7BidI9yrQ5MRbQNv4PsgK/3UGpzCYaNPPbvgr9fe+0jNdJO+uC0+dk4xIzCQ==
"@firebase/auth@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.21.4.tgz#2ce8a34a78b53a168152b987b7bbd844f0431669"
integrity sha512-yZrs1F8sTt8IMCJl29gaxokDZSLjO08r2bL2PNKV1Duz2vJ67ZtVcgHAidyf8BFak9uS8mepd9KlYFDfwUO60Q==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
tslib "^2.1.0"
@@ -334,7 +334,27 @@
"@firebase/util" "1.9.2"
tslib "^2.1.0"
"@firebase/database-compat@0.3.3", "@firebase/database-compat@^0.3.0":
"@firebase/component@0.6.4":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.6.4.tgz#8981a6818bd730a7554aa5e0516ffc9b1ae3f33d"
integrity sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==
dependencies:
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/database-compat@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.3.4.tgz#4e57932f7a5ba761cd5ac946ab6b6ab3f660522c"
integrity sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==
dependencies:
"@firebase/component" "0.6.4"
"@firebase/database" "0.14.4"
"@firebase/database-types" "0.10.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/database-compat@^0.3.0":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.3.3.tgz#4668e32527f57c1dde6cb03f5fde81eb04503ad4"
integrity sha512-r+L9jTbvsnb7sD+xz6UKU39DgBWqB2pyjzPNdBeriGC9Ssa2MAZe0bIqjCQg51RRXYc/aa/zK1Q2/4uesZeVgQ==
@@ -354,6 +374,14 @@
"@firebase/app-types" "0.9.0"
"@firebase/util" "1.9.2"
"@firebase/database-types@0.10.4":
version "0.10.4"
resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.10.4.tgz#47ba81113512dab637abace61cfb65f63d645ca7"
integrity sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==
dependencies:
"@firebase/app-types" "0.9.0"
"@firebase/util" "1.9.3"
"@firebase/database@0.14.3":
version "0.14.3"
resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.14.3.tgz#0ddd92e5eeef2dbebefd55ce78b39472a57dd5d3"
@@ -366,15 +394,27 @@
faye-websocket "0.11.4"
tslib "^2.1.0"
"@firebase/firestore-compat@0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.3.3.tgz#2fedc13e6242aa98a78cfb710242721d9822c1da"
integrity sha512-fMTsSC0s2cF5w2+JoB0dWD/o4kXtLrUCPGnZPuz4S0bqTN2t0vHr3gdAsQLtnadgwB78ACtinYmf4Udwx7TzDg==
"@firebase/database@0.14.4":
version "0.14.4"
resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.14.4.tgz#9e7435a16a540ddfdeb5d99d45618e6ede179aa6"
integrity sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/firestore" "3.8.3"
"@firebase/auth-interop-types" "0.2.1"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
faye-websocket "0.11.4"
tslib "^2.1.0"
"@firebase/firestore-compat@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.3.4.tgz#1c656c225a1ed2a3cd6af1f4118701b5539a4c44"
integrity sha512-xUzz1V53vA1R8S5QQbQ33zqNv0bV+dZpeQKqMXt6HNWa1yiX7lUooGYRws825F+QBOadW1teav1ttXnGZAsgUw==
dependencies:
"@firebase/component" "0.6.4"
"@firebase/firestore" "3.8.4"
"@firebase/firestore-types" "2.5.1"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/firestore-types@2.5.1":
@@ -382,29 +422,29 @@
resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-2.5.1.tgz#464b2ee057956599ca34de50eae957c30fdbabb7"
integrity sha512-xG0CA6EMfYo8YeUxC8FeDzf6W3FX1cLlcAGBYV6Cku12sZRI81oWcu61RSKM66K6kUENP+78Qm8mvroBcm1whw==
"@firebase/firestore@3.8.3":
version "3.8.3"
resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-3.8.3.tgz#8305113b9535747f982b585b0dd72e85122b5b89"
integrity sha512-4xR3Mqj95bxHg3hZnz0O+LQrHkjq+siT2y+B9da6u68qJ8bzzT42JaFgd1vifhbBpVbBzpFaS2RuCq2E+kGv9g==
"@firebase/firestore@3.8.4":
version "3.8.4"
resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-3.8.4.tgz#66b057330a22f0cd240b60746f2b2920b10dee31"
integrity sha512-sNLT4vGBSrx75Q2yLzCHL/1LDS7+UG8gaIohox/GpKYGxt4r8/AsUOmjN4llDqdnFSgY5ePYp2+nHArFXHyZjA==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
"@firebase/webchannel-wrapper" "0.9.0"
"@grpc/grpc-js" "~1.7.0"
"@grpc/proto-loader" "^0.6.13"
node-fetch "2.6.7"
tslib "^2.1.0"
"@firebase/functions-compat@0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.3.3.tgz#530c30b4dfea14e71657f780d2c281e16209aed7"
integrity sha512-UIAJ2gzNq0p/61cXqkpi9DnlQt0hdlGqgmL5an7KuJth2Iv5uGpKg/+OapAZxPuiUNZgTEyZDB7kNBHvnxWq5w==
"@firebase/functions-compat@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.3.4.tgz#2b37321d893e816fec80435bb7cbca90f293bc0d"
integrity sha512-kxVxTGyLV1MBR3sp3mI+eQ6JBqz0G5bk310F8eX4HzDFk4xjk5xY0KdHktMH+edM2xs1BOg0vwvvsAHczIjB+w==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/functions" "0.9.3"
"@firebase/component" "0.6.4"
"@firebase/functions" "0.9.4"
"@firebase/functions-types" "0.6.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/functions-types@0.6.0":
@@ -412,28 +452,28 @@
resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.0.tgz#ccd7000dc6fc668f5acb4e6a6a042a877a555ef2"
integrity sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==
"@firebase/functions@0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.9.3.tgz#9ef33efcd38b0235e84ae472d9b51597efe3f871"
integrity sha512-tPJgYY2ROQSYuzvgxZRoHeDj+Ic07/bWHwaftgTriawtupmFOkt5iikuhJSJUhaOpFh9TB335OvCXJw1N+BIlQ==
"@firebase/functions@0.9.4":
version "0.9.4"
resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.9.4.tgz#47232500be6847f1c7d3fa74eb36f621bd01a160"
integrity sha512-3H2qh6U+q+nepO5Hds+Ddl6J0pS+zisuBLqqQMRBHv9XpWfu0PnDHklNmE8rZ+ccTEXvBj6zjkPfdxt6NisvlQ==
dependencies:
"@firebase/app-check-interop-types" "0.2.0"
"@firebase/auth-interop-types" "0.2.1"
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/messaging-interop-types" "0.2.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
tslib "^2.1.0"
"@firebase/installations-compat@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.3.tgz#42b05f4e5204c354e0fa059378402bd47635e5bf"
integrity sha512-K9rKM/ym06lkpaKz7bMLxzHK/HEk65XfLJBV+dJkIuWeO0EqqC9VFGrpWAo0QmgC4BqbU58T6VBbzoJjb0gaFw==
"@firebase/installations-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.4.tgz#b5557c897b4cd3635a59887a8bf69c3731aaa952"
integrity sha512-LI9dYjp0aT9Njkn9U4JRrDqQ6KXeAmFbRC0E7jI7+hxl5YmRWysq5qgQl22hcWpTk+cm3es66d/apoDU/A9n6Q==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/installations" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/installations-types" "0.5.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/installations-types@0.5.0":
@@ -441,13 +481,13 @@
resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.0.tgz#2adad64755cd33648519b573ec7ec30f21fb5354"
integrity sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==
"@firebase/installations@0.6.3":
version "0.6.3"
resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.3.tgz#b833cf12ac63666246a57100dbdd669fb76a23aa"
integrity sha512-20JFWm+tweNoRjRbz8/Y4I7O5pUJGZsFKCkLl1qNxfNYECSfrZUuozIDJDZC/MeVn5+kB9CwjThDlgQEPrfLdg==
"@firebase/installations@0.6.4":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.4.tgz#20382e33e6062ac5eff4bede8e468ed4c367609e"
integrity sha512-u5y88rtsp7NYkCHC3ElbFBrPtieUybZluXyzl7+4BsIz4sqb4vSAuwHEUgCgCeaQhvsnxDEU6icly8U9zsJigA==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/util" "1.9.2"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
idb "7.0.1"
tslib "^2.1.0"
@@ -458,14 +498,14 @@
dependencies:
tslib "^2.1.0"
"@firebase/messaging-compat@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.3.tgz#2d222e4078643e49a708b61b6d0e51edc2bc73bd"
integrity sha512-MmuuohXV2YRzIoJmDngI5qqO/cF2q7SdAaw7k4r61W3ReJy7x4/rtqrIvwNVhM6X/X8NFGBbsYKsCfRHWjFdkg==
"@firebase/messaging-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.4.tgz#323ca48deef77065b4fcda3cfd662c4337dffcfd"
integrity sha512-lyFjeUhIsPRYDPNIkYX1LcZMpoVbBWXX4rPl7c/rqc7G+EUea7IEtSt4MxTvh6fDfPuzLn7+FZADfscC+tNMfg==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/messaging" "0.12.3"
"@firebase/util" "1.9.2"
"@firebase/component" "0.6.4"
"@firebase/messaging" "0.12.4"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/messaging-interop-types@0.2.0":
@@ -473,28 +513,28 @@
resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz#6056f8904a696bf0f7fdcf5f2ca8f008e8f6b064"
integrity sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==
"@firebase/messaging@0.12.3":
version "0.12.3"
resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.3.tgz#3fd521e31deb9b81ec6316062deb1dcc8198d038"
integrity sha512-a3ZKcGDiV2sKmQDB56PpgL1yjFxXCtff2+v1grnAZZ4GnfNQ74t2EHCbmgY7xRX7ThzMqug54oxhuk4ur0MIoA==
"@firebase/messaging@0.12.4":
version "0.12.4"
resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.4.tgz#ccb49df5ab97d5650c9cf5b8c77ddc34daafcfe0"
integrity sha512-6JLZct6zUaex4g7HI3QbzeUrg9xcnmDAPTWpkoMpd/GoSVWH98zDoWXMGrcvHeCAIsLpFMe4MPoZkJbrPhaASw==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/installations" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/messaging-interop-types" "0.2.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
idb "7.0.1"
tslib "^2.1.0"
"@firebase/performance-compat@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.3.tgz#f3939bedc2017a95772fde64a72e97fe4b184268"
integrity sha512-I3rqZsIhauXn4iApfj1ttKQdlti/r8OZBG4YK10vxKSdhAzTIDWDKEsdoCXvvKLwplcMv36sM3WPAPGQLqY5MQ==
"@firebase/performance-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.4.tgz#95cbf32057b5d9f0c75d804bc50e6ed3ba486274"
integrity sha512-nnHUb8uP9G8islzcld/k6Bg5RhX62VpbAb/Anj7IXs/hp32Eb2LqFPZK4sy3pKkBUO5wcrlRWQa6wKOxqlUqsg==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/performance" "0.6.3"
"@firebase/performance" "0.6.4"
"@firebase/performance-types" "0.2.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/performance-types@0.2.0":
@@ -502,27 +542,27 @@
resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.0.tgz#400685f7a3455970817136d9b48ce07a4b9562ff"
integrity sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==
"@firebase/performance@0.6.3":
version "0.6.3"
resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.6.3.tgz#663c468dc4d62b6e211938377e21a01854803646"
integrity sha512-NQmQN6Ete7i9jz1mzULJZEGvsOmwwdUy6vpqnhUxSFMYPnlBKjX+yypCUUJDDN5zff5+kfwSD1qCyUAaS0xWUA==
"@firebase/performance@0.6.4":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.6.4.tgz#0ad766bfcfab4f386f4fe0bef43bbcf505015069"
integrity sha512-HfTn/bd8mfy/61vEqaBelNiNnvAbUtME2S25A67Nb34zVuCSCRIX4SseXY6zBnOFj3oLisaEqhVcJmVPAej67g==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/installations" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/remote-config-compat@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.3.tgz#b0c0ef9978186bc58b262a39b9a41ec1bf819df3"
integrity sha512-w/ZL03YgYaXq03xIRyJ5oPhXZi6iDsY/v0J9Y7I7SqxCYytEnHVrL9nvBqd9R94y5LRAVNPCLokJeeizaUz4VQ==
"@firebase/remote-config-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.4.tgz#1f494c81a6c9560b1f9ca1b4fbd4bbbe47cf4776"
integrity sha512-FKiki53jZirrDFkBHglB3C07j5wBpitAaj8kLME6g8Mx+aq7u9P7qfmuSRytiOItADhWUj7O1JIv7n9q87SuwA==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/remote-config" "0.4.3"
"@firebase/remote-config" "0.4.4"
"@firebase/remote-config-types" "0.3.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/remote-config-types@0.3.0":
@@ -530,26 +570,26 @@
resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz#689900dcdb3e5c059e8499b29db393e4e51314b4"
integrity sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==
"@firebase/remote-config@0.4.3":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.4.3.tgz#85c4934d093a4c7b8a336af70ada83e936347a2b"
integrity sha512-Q6d4jBWZoNt6SYq87bjtDGUHFkKwAmGnNjWyRjl14AZqE1ilgd9NZHmutharlYJ3LvxMsid80HdK5SgGEpIPfg==
"@firebase/remote-config@0.4.4":
version "0.4.4"
resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.4.4.tgz#6a496117054de58744bc9f382d2a6d1e14060c65"
integrity sha512-x1ioTHGX8ZwDSTOVp8PBLv2/wfwKzb4pxi0gFezS5GCJwbLlloUH4YYZHHS83IPxnua8b6l0IXUaWd0RgbWwzQ==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/installations" "0.6.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/storage-compat@0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.3.1.tgz#b8536c3a435f8ce5eb07796ca10fda16896a9bae"
integrity sha512-6HaTvWsT5Yy3j4UpCZpMcFUYEkJ2XYWukdyTl02u6VjSBRLvkhOXPzEfMvgVWqhnF/rYVfPdjrZ904wk5OxtmQ==
"@firebase/storage-compat@0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.3.2.tgz#51a97170fd652a516f729f82b97af369e5a2f8d7"
integrity sha512-wvsXlLa9DVOMQJckbDNhXKKxRNNewyUhhbXev3t8kSgoCotd1v3MmqhKKz93ePhDnhHnDs7bYHy+Qa8dRY6BXw==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/storage" "0.11.1"
"@firebase/component" "0.6.4"
"@firebase/storage" "0.11.2"
"@firebase/storage-types" "0.8.0"
"@firebase/util" "1.9.2"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/storage-types@0.8.0":
@@ -557,13 +597,13 @@
resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.0.tgz#f1e40a5361d59240b6e84fac7fbbbb622bfaf707"
integrity sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==
"@firebase/storage@0.11.1":
version "0.11.1"
resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.11.1.tgz#602ddb7bce77077800a46bcdfa76f36d7a265c51"
integrity sha512-Xv8EG2j52ugF2xayBz26U9J0VBXHXPMVxSN+ph3R3BSoHxvMLaPu+qUYKHavSt+zbcgPH2GyBhrCdJK6SaDFPA==
"@firebase/storage@0.11.2":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.11.2.tgz#c5e0316543fe1c4026b8e3910f85ad73f5b77571"
integrity sha512-CtvoFaBI4hGXlXbaCHf8humajkbXhs39Nbh6MbNxtwJiCqxPy9iH3D3CCfXAvP0QvAAwmJUTK3+z9a++Kc4nkA==
dependencies:
"@firebase/component" "0.6.3"
"@firebase/util" "1.9.2"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
tslib "^2.1.0"
@@ -574,6 +614,13 @@
dependencies:
tslib "^2.1.0"
"@firebase/util@1.9.3":
version "1.9.3"
resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.9.3.tgz#45458dd5cd02d90e55c656e84adf6f3decf4b7ed"
integrity sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==
dependencies:
tslib "^2.1.0"
"@firebase/webchannel-wrapper@0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.9.0.tgz#9340bce56560a8bdba1d25d6281d4bfc397450dc"
@@ -679,9 +726,9 @@
yargs "^16.2.0"
"@headlessui/react@^1.7.11":
version "1.7.12"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.12.tgz#9ab2baa3c4f632782631e00937f9531a34033619"
integrity sha512-FhSx5V+Qp0GvbTpaxyS+ymGDDNntCacClWsk/d8Upbr19g3AsPbjfPk4+m2CgJGcuCB5Dz7LpUIOAbvQTyjL2g==
version "1.7.13"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.13.tgz#fd150b394954e9f1d86ed2340cffd1217d6e7628"
integrity sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==
dependencies:
client-only "^0.0.1"
@@ -737,10 +784,10 @@
dependencies:
glob "7.1.7"
"@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/font@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/font/-/font-13.2.3.tgz#96d8a1b431425b47e01f3620118d570e2148e312"
integrity sha512-7EHzk0f7FVYICLUZTpyPk93IfcTUao++Xt1Sgb+Zk5dVOCYHabqLtlF5ywSoXIqyFlo0qlshEBxsrzHAGTWkDw==
"@next/swc-android-arm-eabi@13.2.3":
version "13.2.3"
@@ -1048,15 +1095,15 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
"@types/node@*":
version "18.14.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.4.tgz#0e64ec0b35a772e1e3d849f9a0ff61782d0cb647"
integrity sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g==
"@types/node@18.14.2":
version "18.14.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.2.tgz#c076ed1d7b6095078ad3cf21dfeea951842778b1"
integrity sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==
"@types/node@18.14.6", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
version "18.14.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.6.tgz#ae1973dd2b1eeb1825695bb11ebfb746d27e3e93"
integrity sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==
"@types/parse-json@^4.0.0":
version "4.0.0"
@@ -2572,36 +2619,36 @@ firebase-functions@^4.2.1:
node-fetch "^2.6.7"
firebase@^9.17.1:
version "9.17.1"
resolved "https://registry.yarnpkg.com/firebase/-/firebase-9.17.1.tgz#91c56fe9d9bf5ed1c405030e4fe8133c6069fd40"
integrity sha512-MSZaTRaaRLgDFLqoEnoPYK8zkLwQNvYeLZ3YSKdcQxG8hDifNO22ywS1cSA1ZCGHlQeOsDtfDwBejKcANf/RQw==
version "9.17.2"
resolved "https://registry.yarnpkg.com/firebase/-/firebase-9.17.2.tgz#950720666b1628a0b16926fbea4fc4217bd66185"
integrity sha512-2V95/evwB3zsi6RYHCvPXfkiQrSepFQJohv3YGoQVhS0bvXuYXmkLtrCVGShxneB/5t9HE5C9q9C8XPnK4APBw==
dependencies:
"@firebase/analytics" "0.9.3"
"@firebase/analytics-compat" "0.2.3"
"@firebase/app" "0.9.3"
"@firebase/app-check" "0.6.3"
"@firebase/app-check-compat" "0.3.3"
"@firebase/app-compat" "0.2.3"
"@firebase/analytics" "0.9.4"
"@firebase/analytics-compat" "0.2.4"
"@firebase/app" "0.9.4"
"@firebase/app-check" "0.6.4"
"@firebase/app-check-compat" "0.3.4"
"@firebase/app-compat" "0.2.4"
"@firebase/app-types" "0.9.0"
"@firebase/auth" "0.21.3"
"@firebase/auth-compat" "0.3.3"
"@firebase/database" "0.14.3"
"@firebase/database-compat" "0.3.3"
"@firebase/firestore" "3.8.3"
"@firebase/firestore-compat" "0.3.3"
"@firebase/functions" "0.9.3"
"@firebase/functions-compat" "0.3.3"
"@firebase/installations" "0.6.3"
"@firebase/installations-compat" "0.2.3"
"@firebase/messaging" "0.12.3"
"@firebase/messaging-compat" "0.2.3"
"@firebase/performance" "0.6.3"
"@firebase/performance-compat" "0.2.3"
"@firebase/remote-config" "0.4.3"
"@firebase/remote-config-compat" "0.2.3"
"@firebase/storage" "0.11.1"
"@firebase/storage-compat" "0.3.1"
"@firebase/util" "1.9.2"
"@firebase/auth" "0.21.4"
"@firebase/auth-compat" "0.3.4"
"@firebase/database" "0.14.4"
"@firebase/database-compat" "0.3.4"
"@firebase/firestore" "3.8.4"
"@firebase/firestore-compat" "0.3.4"
"@firebase/functions" "0.9.4"
"@firebase/functions-compat" "0.3.4"
"@firebase/installations" "0.6.4"
"@firebase/installations-compat" "0.2.4"
"@firebase/messaging" "0.12.4"
"@firebase/messaging-compat" "0.2.4"
"@firebase/performance" "0.6.4"
"@firebase/performance-compat" "0.2.4"
"@firebase/remote-config" "0.4.4"
"@firebase/remote-config-compat" "0.2.4"
"@firebase/storage" "0.11.2"
"@firebase/storage-compat" "0.3.2"
"@firebase/util" "1.9.3"
fireschema@^4.0.4:
version "4.0.4"
@@ -2903,10 +2950,10 @@ googleapis-common@^6.0.0:
url-template "^2.0.8"
uuid "^9.0.0"
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==
googleapis@112.0.0:
version "112.0.0"
resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-112.0.0.tgz#e957811a1df3c408f934c0047e091d5d8f14b7ef"
integrity sha512-WPfXhYZVrbbJRxB+ZZDksjuelmt49Mcl/1mo7w05kvLS1EbynvTELsNTJwh+hNrjsFKdh4izWLAcjTDo0Boycg==
dependencies:
google-auth-library "^8.0.2"
googleapis-common "^6.0.0"
@@ -4355,9 +4402,9 @@ react-firebase-hooks@^3.0.3:
integrity sha512-9LztZGaZU0qJY/TQWzkBlfVrFmu0Ui6HE8CUjU7tNz9oGKGx5tUQG/xQbfyMIGClErgnnQsm8sC+oU9pg8Ri5Q==
react-hook-form@^7.43.2:
version "7.43.3"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.43.3.tgz#780af64ea1f3c5864626a377e302bfcc7750af6f"
integrity sha512-LV6Fixh+hirrl6dXbM78aB6n//82aKbsNbcofF3wc6nx1UJLu3Jj/gsg1E5C9iISnLX+du8VTUyBUz2aCy+H7w==
version "7.43.4"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.43.4.tgz#32c12cce916e2ba50178148a5ef5acffeaae2a3e"
integrity sha512-JZp05wvmuV8qr3NNDWwyhiQL05sh9E8x/2NoWtkdiyyiezmwOr5pKexlvbCEfBMa7ZYrvzk88G/uhLl47T9b7Q==
react-hot-toast@^2.4.0:
version "2.4.0"
@@ -4367,9 +4414,9 @@ react-hot-toast@^2.4.0:
goober "^2.1.10"
react-icons@^4.7.1:
version "4.7.1"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.7.1.tgz#0f4b25a5694e6972677cb189d2a72eabea7a8345"
integrity sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==
version "4.8.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.8.0.tgz#621e900caa23b912f737e41be57f27f6b2bff445"
integrity sha512-N6+kOLcihDiAnj5Czu637waJqSnwlMNROzVZMhfX68V/9bu9qHaMIJC4UdozWoOk57gahFCNHwVvWzm0MTzRjg==
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
@@ -4891,9 +4938,9 @@ text-table@^0.2.0:
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
theme-change@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/theme-change/-/theme-change-2.4.0.tgz#db9e7fded16a2fcd5555e19fa3755ef9ff4996da"
integrity sha512-HbMckoxM7sV8L7wk53S5ceiBQWcTxFozuvUmvjdjPqpyVFkzPQHylSsDHYyT8qTruORe+1Sft7ExqlXQEeWHBA==
version "2.5.0"
resolved "https://registry.yarnpkg.com/theme-change/-/theme-change-2.5.0.tgz#d3b064af9c4cd01ab16ce0a4ecb251c827a50e68"
integrity sha512-B/UdsgdHAGhSKHTAQnxg/etN0RaMDpehuJmZIjLMDVJ6DGIliRHGD6pODi1CXLQAN9GV0GSyB3G6yCuK05PkPQ==
thread-stream@^0.15.1:
version "0.15.2"
@@ -5287,6 +5334,6 @@ yocto-queue@^0.1.0:
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zod@^3.20.6:
version "3.20.6"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.20.6.tgz#2f2f08ff81291d47d99e86140fedb4e0db08361a"
integrity sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==
version "3.21.1"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.1.tgz#ac5bb7cf68876281ebd02f95ac4bb9a080370282"
integrity sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==