diff --git a/.DS_Store b/.DS_Store index 3671182f..4115d15b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/dashboard/page.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/dashboard/page.tsx index e385c1cd..494fafb5 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/dashboard/page.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/dashboard/page.tsx @@ -1,39 +1,54 @@ -import { - fetchSlimOrganizations, - getDefaultOrganization, - getOrganizationSlugByOrganizationId, -} from '@/data/user/organizations'; -import { notFound, redirect } from 'next/navigation'; +'use client' + +import { getInitialOrganizationToRedirectTo } from '@/data/user/organizations'; +import { useSAToastMutation } from '@/hooks/useSAToastMutation'; +import { motion } from 'framer-motion'; +import { useRouter } from 'next/navigation'; +import { useDidMount } from 'rooks'; + +const containerVariants = { + hidden: { opacity: 0 }, + visible: { opacity: 1, transition: { duration: 0.5 } }, + exit: { opacity: 0, transition: { duration: 0.5 } }, +}; + +export default function DashboardPage() { + const router = useRouter(); + + const initialOrgRedirectMutation = useSAToastMutation(getInitialOrganizationToRedirectTo, { + loadingMessage: 'Loading your dashboard...', + errorMessage: 'Failed to load dashboard', + successMessage: 'Redirecting to your dashboard...', + onSuccess: (successPayload) => { + router.push(`/${successPayload.data}`); + }, + onError: (errorPayload) => { + console.error(errorPayload); + }, + }); + + useDidMount(() => { + initialOrgRedirectMutation.mutate(); + }); -async function getOrganizationToRedirectTo(): Promise { - const [slimOrganizations, defaultOrganizationId] = await Promise.all([ - fetchSlimOrganizations(), - getDefaultOrganization(), - ]); - - const firstOrganization = slimOrganizations[0]; - - if (defaultOrganizationId) { - return await getOrganizationSlugByOrganizationId(defaultOrganizationId); - } - - // this condition is unreachable as the parent ../layout component ensures at least - // one organization exists - if (!firstOrganization) { - return notFound(); - } - - - return firstOrganization.slug; -} - -async function RedirectToDefaultOrg() { - const firstOrganizationId = await getOrganizationToRedirectTo(); - return redirect(`/${firstOrganizationId}`); -} - -export default async function DashboardPage() { return ( - + + {initialOrgRedirectMutation.isLoading && ( + + Loading your dashboard... + + )} + ); } diff --git a/src/app/(dynamic-pages)/(login-pages)/login/Login.tsx b/src/app/(dynamic-pages)/(login-pages)/login/Login.tsx index 5087186f..920257a0 100644 --- a/src/app/(dynamic-pages)/(login-pages)/login/Login.tsx +++ b/src/app/(dynamic-pages)/(login-pages)/login/Login.tsx @@ -17,8 +17,10 @@ import { signInWithPassword, signInWithProvider, } from '@/data/auth/auth'; +import { getInitialOrganizationToRedirectTo } from '@/data/user/organizations'; import { useSAToastMutation } from '@/hooks/useSAToastMutation'; import type { AuthProvider } from '@/types'; +import { PrefetchKind } from 'next/dist/client/components/router-reducer/router-reducer-types'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { useDidMount } from 'rooks'; @@ -37,15 +39,29 @@ export function Login({ useDidMount(() => { console.log('prefetching dashboard') - router.prefetch('/dashboard') + router.prefetch('/dashboard', { + kind: PrefetchKind.AUTO + }) }) + const initialOrgRedirectMutation = useSAToastMutation(getInitialOrganizationToRedirectTo, { + loadingMessage: 'Loading your dashboard...', + errorMessage: 'Failed to load dashboard', + successMessage: 'Redirecting to your dashboard...', + onSuccess: (successPayload) => { + router.push(`/${successPayload.data}`); + }, + onError: (errorPayload) => { + console.error(errorPayload); + }, + }); + + function redirectToDashboard() { - router.refresh(); if (next) { router.push(`/auth/callback?next=${next}`); } else { - router.push('/auth/callback'); + initialOrgRedirectMutation.mutate(); } } const magicLinkMutation = useSAToastMutation( diff --git a/src/app/(dynamic-pages)/(login-pages)/login/NewLogin.tsx b/src/app/(dynamic-pages)/(login-pages)/login/NewLogin.tsx new file mode 100644 index 00000000..c7dfa40f --- /dev/null +++ b/src/app/(dynamic-pages)/(login-pages)/login/NewLogin.tsx @@ -0,0 +1,169 @@ + +import { Button } from "@/components/ui/button" +import { Card } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import Link from "next/link" + +export function NewLoginPage() { + return ( +
+
+ +
+

Welcome Back

+

Please log in to your account

+
+ + + Magic Link + Email & Password + + +
+
+ + +
+ +
+
+ +
+
+ + +
+
+ + +
+ +
+
+
+
+
Or login with
+
+ + + +
+
+
+ + Already have an account? + + + Forgot password? + +
+
+
+
+ Background Image +
+
+ ) +} + +function ChromeIcon(props) { + return ( + + + + + + + + ) +} + + +function GithubIcon(props) { + return ( + + + + + ) +} + + +function TwitterIcon(props) { + return ( + + + + ) +} + + +function XIcon(props) { + return ( + + + + + ) +} diff --git a/src/app/favicon.ico b/src/app/favicon.ico new file mode 100644 index 00000000..7a9c7834 Binary files /dev/null and b/src/app/favicon.ico differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index bb136544..6998ca25 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,10 +1,11 @@ import '@/styles/globals.css'; import '@/styles/prosemirror.css'; import { GeistSans } from 'geist/font/sans'; +import { Metadata } from 'next'; import 'server-only'; import { AppProviders } from './AppProviders'; -export const metadata = { +export const metadata: Metadata = { icons: { icon: '/images/logo-black-main.ico', }, diff --git a/src/components/Auth/RedirectingPleaseWaitCard.tsx b/src/components/Auth/RedirectingPleaseWaitCard.tsx index ab546c4a..becd4ff6 100644 --- a/src/components/Auth/RedirectingPleaseWaitCard.tsx +++ b/src/components/Auth/RedirectingPleaseWaitCard.tsx @@ -26,9 +26,7 @@ export function RedirectingPleaseWaitCard({ {heading} {message} - - ); } diff --git a/src/data/user/organizations.ts b/src/data/user/organizations.ts index 28864903..9b3aee9e 100644 --- a/src/data/user/organizations.ts +++ b/src/data/user/organizations.ts @@ -566,3 +566,40 @@ export const updateOrganizationSlug = async ( revalidatePath("/[organizationSlug]", 'layout'); return { status: 'success', data: `Slug updated to ${newSlug}` }; }; + + + +/** + * This is the organization that the user will be redirected to once they login + * or when they go to the /dashboard page + */ +export async function getInitialOrganizationToRedirectTo(): Promise> { + const [slimOrganizations, defaultOrganizationId] = await Promise.all([ + fetchSlimOrganizations(), + getDefaultOrganization(), + ]); + + const firstOrganization = slimOrganizations[0]; + + if (defaultOrganizationId) { + const slug = await getOrganizationSlugByOrganizationId(defaultOrganizationId); + return { + data: slug, + status: 'success', + }; + } + + // this condition is unreachable as the parent ../layout component ensures at least + // one organization exists + if (!firstOrganization) { + return { + message: 'No organizations found', + status: 'error', + }; + } + + return { + data: firstOrganization.slug, + status: 'success', + }; +}