Merge pull request 'feat(firebase): Add Firebase SDK and initialize Analytics' (#44) from device-token into develop
Reviewed-on: https://repo.ravanertebat.com/TM/tm_panel/pulls/44 Reviewed-by: Sina Nakhostin <s.nakhostin@ravanertebat.com>
This commit is contained in:
@@ -1,2 +1,9 @@
|
|||||||
NEXT_PUBLIC_API_URL="https://admin.opplens.com/admin/v1/"
|
NEXT_PUBLIC_API_URL="https://admin.opplens.com/admin/v1/"
|
||||||
NEXT_PUBLIC_TOAST_AUTO_CLOSE_DURATION=2500
|
NEXT_PUBLIC_TOAST_AUTO_CLOSE_DURATION=2500
|
||||||
|
NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSyCTjdsk2jE34IfnvSKP1JMTIf_Abd7tbt0
|
||||||
|
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=opplens-270d1.firebaseapp.com
|
||||||
|
NEXT_PUBLIC_FIREBASE_PROJECT_ID=opplens-270d1
|
||||||
|
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=opplens-270d1.firebasestorage.app
|
||||||
|
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=6923326255
|
||||||
|
NEXT_PUBLIC_FIREBASE_APP_ID=1:6923326255:web:584a017e8e1bd0e4ed87da
|
||||||
|
NEXT_PUBLIC_FIREBASE_MEASURMENT_ID=G-VQW40G8VKC
|
||||||
|
|||||||
Generated
+1016
-7
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"currency-symbol-map": "^5.1.0",
|
"currency-symbol-map": "^5.1.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"firebase": "^12.3.0",
|
||||||
"flatpickr": "^4.6.13",
|
"flatpickr": "^4.6.13",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jsvectormap": "^1.6.0",
|
"jsvectormap": "^1.6.0",
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
importScripts("https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js");
|
||||||
|
importScripts(
|
||||||
|
"https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js",
|
||||||
|
);
|
||||||
|
|
||||||
|
firebase.initializeApp({
|
||||||
|
apiKey: "AIzaSyCTjdsk2jE34IfnvSKP1JMTIf_Abd7tbt0",
|
||||||
|
authDomain: "opplens-270d1.firebaseapp.com",
|
||||||
|
projectId: "opplens-270d1",
|
||||||
|
storageBucket: "opplens-270d1.firebasestorage.app",
|
||||||
|
messagingSenderId: "6923326255",
|
||||||
|
appId: "1:6923326255:web:584a017e8e1bd0e4ed87da",
|
||||||
|
measurementId: "G-VQW40G8VKC",
|
||||||
|
});
|
||||||
|
|
||||||
|
const messaging = firebase.messaging();
|
||||||
@@ -3,6 +3,7 @@ import "@/css/style.css";
|
|||||||
import "react-tooltip/dist/react-tooltip.css";
|
import "react-tooltip/dist/react-tooltip.css";
|
||||||
|
|
||||||
import { ConditionalLayout } from "@/components/Layouts/conditional-layout";
|
import { ConditionalLayout } from "@/components/Layouts/conditional-layout";
|
||||||
|
import FirebaseProvider from "@/components/Layouts/firebase-provider";
|
||||||
import "flatpickr/dist/flatpickr.min.css";
|
import "flatpickr/dist/flatpickr.min.css";
|
||||||
import "jsvectormap/dist/jsvectormap.css";
|
import "jsvectormap/dist/jsvectormap.css";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
@@ -27,9 +28,11 @@ export default function RootLayout({ children }: PropsWithChildren) {
|
|||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<body>
|
<body>
|
||||||
<Providers>
|
<Providers>
|
||||||
|
<FirebaseProvider>
|
||||||
<NextTopLoader color="#5750F1" showSpinner={false} />
|
<NextTopLoader color="#5750F1" showSpinner={false} />
|
||||||
|
|
||||||
<ConditionalLayout>{children}</ConditionalLayout>
|
<ConditionalLayout>{children}</ConditionalLayout>
|
||||||
|
</FirebaseProvider>
|
||||||
</Providers>
|
</Providers>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { PasswordIcon, UserIcon } from "@/assets/icons";
|
import { PasswordIcon, UserIcon } from "@/assets/icons";
|
||||||
|
|
||||||
|
import { FormErrorMessages } from "@/constants/Texts";
|
||||||
import { useLoginQuery } from "@/hooks/queries";
|
import { useLoginQuery } from "@/hooks/queries";
|
||||||
import { ILoginCredentials } from "@/lib/api";
|
import { ILoginCredentials } from "@/lib/api";
|
||||||
|
import { COOKIE_KEYS } from "@/lib/shared/cookies";
|
||||||
|
import { useIsMutating } from "@tanstack/react-query";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { SubmitHandler, useForm } from "react-hook-form";
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
import InputGroup from "../FormElements/InputGroup";
|
import InputGroup from "../FormElements/InputGroup";
|
||||||
|
|
||||||
import { FormErrorMessages } from "@/constants/Texts";
|
|
||||||
import { useIsMutating } from "@tanstack/react-query";
|
|
||||||
|
|
||||||
export default function SigninWithPassword() {
|
export default function SigninWithPassword() {
|
||||||
const isMutating = useIsMutating();
|
const isMutating = useIsMutating();
|
||||||
const [passwordFieldInputType, setPasswordFieldInputType] = useState<
|
const [passwordFieldInputType, setPasswordFieldInputType] = useState<
|
||||||
@@ -20,7 +21,10 @@ export default function SigninWithPassword() {
|
|||||||
const { mutate } = useLoginQuery(reset);
|
const { mutate } = useLoginQuery(reset);
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<ILoginCredentials> = (data) => {
|
const onSubmit: SubmitHandler<ILoginCredentials> = (data) => {
|
||||||
mutate(data);
|
mutate({
|
||||||
|
...data,
|
||||||
|
device_token: Cookies.get(COOKIE_KEYS.device_token) ?? "",
|
||||||
|
});
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { AuthGuard, LoginGuard } from "@/contexts";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import type { PropsWithChildren } from "react";
|
import type { PropsWithChildren } from "react";
|
||||||
import { Header } from "./header";
|
import { Header } from "./header";
|
||||||
|
import Notification from "./notification";
|
||||||
import { Sidebar } from "./sidebar";
|
import { Sidebar } from "./sidebar";
|
||||||
import { AuthGuard, LoginGuard } from "@/contexts";
|
|
||||||
|
|
||||||
export function ConditionalLayout({ children }: PropsWithChildren) {
|
export function ConditionalLayout({ children }: PropsWithChildren) {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const isAuthPage = pathname.startsWith("/auth");
|
const isAuthPage = pathname.startsWith("/auth");
|
||||||
@@ -18,6 +18,7 @@ export function ConditionalLayout({ children }: PropsWithChildren) {
|
|||||||
</LoginGuard>
|
</LoginGuard>
|
||||||
) : (
|
) : (
|
||||||
<AuthGuard>
|
<AuthGuard>
|
||||||
|
<Notification>
|
||||||
<div className="flex min-h-screen">
|
<div className="flex min-h-screen">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className="w-full bg-gray-2 dark:bg-[#020d1a]">
|
<div className="w-full bg-gray-2 dark:bg-[#020d1a]">
|
||||||
@@ -27,6 +28,7 @@ export function ConditionalLayout({ children }: PropsWithChildren) {
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Notification>
|
||||||
</AuthGuard>
|
</AuthGuard>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import useFirebase from "@/hooks/use-firebase";
|
||||||
|
import type { PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
const FirebaseProvider = ({ children }: PropsWithChildren) => {
|
||||||
|
useFirebase();
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FirebaseProvider;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { onMessage } from "firebase/messaging";
|
||||||
|
import { useEffect, type PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
import { messaging } from "@/services/firebase";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
const Notification = ({ children }: PropsWithChildren) => {
|
||||||
|
useEffect(() => {
|
||||||
|
onMessage(messaging, (payload) => {
|
||||||
|
console.log("Message received. ", payload);
|
||||||
|
if (payload.notification) {
|
||||||
|
toast.success(payload.notification.title ?? "New Notification");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Notification;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { requestForToken } from "../services/firebase";
|
||||||
|
|
||||||
|
const useFirebase = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
requestForToken();
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useFirebase;
|
||||||
@@ -45,6 +45,7 @@ export const CreateAdminSchema = z.object({
|
|||||||
export const LoginCredentials = z.object({
|
export const LoginCredentials = z.object({
|
||||||
username: z.string(),
|
username: z.string(),
|
||||||
password: z.string(),
|
password: z.string(),
|
||||||
|
device_token: z.string(),
|
||||||
});
|
});
|
||||||
export const AdminListResponse = z.object({
|
export const AdminListResponse = z.object({
|
||||||
users: z.array(UserSchema),
|
users: z.array(UserSchema),
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ export const COOKIE_KEYS = {
|
|||||||
theme: `${_COOKIE_PREFIX}_theme`,
|
theme: `${_COOKIE_PREFIX}_theme`,
|
||||||
refresh_token: `${_COOKIE_PREFIX}_refresh_token`,
|
refresh_token: `${_COOKIE_PREFIX}_refresh_token`,
|
||||||
user: `${_COOKIE_PREFIX}_user`,
|
user: `${_COOKIE_PREFIX}_user`,
|
||||||
|
device_token: `${_COOKIE_PREFIX}_device_token`,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { COOKIE_KEYS } from "@/lib/shared/cookies";
|
||||||
|
import { initializeApp } from "firebase/app";
|
||||||
|
import { getMessaging, getToken } from "firebase/messaging";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
const firebaseConfig = {
|
||||||
|
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
||||||
|
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
||||||
|
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
||||||
|
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
||||||
|
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
||||||
|
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const app = initializeApp(firebaseConfig);
|
||||||
|
export const messaging = getMessaging(app);
|
||||||
|
|
||||||
|
export const requestForToken = () => {
|
||||||
|
return getToken(messaging)
|
||||||
|
.then((currentToken) => {
|
||||||
|
if (currentToken) {
|
||||||
|
console.log("current token for client: ", currentToken);
|
||||||
|
Cookies.set(COOKIE_KEYS.device_token, currentToken);
|
||||||
|
} else {
|
||||||
|
// Show permission request UI
|
||||||
|
console.log(
|
||||||
|
"No registration token available. Request permission to generate one.",
|
||||||
|
);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("An error occurred while retrieving token. ", err);
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user