Skip to content

Commit

Permalink
refactor: replace zustand with context for modals
Browse files Browse the repository at this point in the history
  • Loading branch information
mickasmt committed Jun 3, 2024
1 parent 0d9620e commit db932c9
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 155 deletions.
5 changes: 2 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ThemeProvider } from "next-themes";
import { cn, constructMetadata } from "@/lib/utils";
import { Toaster } from "@/components/ui/toaster";
import { Analytics } from "@/components/analytics";
import { ModalProvider } from "@/components/modal-provider";
import ModalProvider from "@/components/modals/providers";
import { TailwindIndicator } from "@/components/tailwind-indicator";

interface RootLayoutProps {
Expand Down Expand Up @@ -35,10 +35,9 @@ export default function RootLayout({ children }: RootLayoutProps) {
enableSystem
disableTransitionOnChange
>
{children}
<ModalProvider>{children}</ModalProvider>
<Analytics />
<Toaster />
<ModalProvider />
<TailwindIndicator />
</ThemeProvider>
</SessionProvider>
Expand Down
21 changes: 11 additions & 10 deletions components/layout/navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
"use client";

import { useSession } from "next-auth/react";
import Link from "next/link";
import { useSelectedLayoutSegment } from "next/navigation";
import { useSession } from "next-auth/react";
import { useContext } from "react";

import { DocsSearch } from "@/components/docs/search";
import { ModalContext } from "@/components/modals/providers";
import { Icons } from "@/components/shared/icons";
import MaxWidthWrapper from "@/components/shared/max-width-wrapper";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { dashboardConfig } from "@/config/dashboard";
import { docsConfig } from "@/config/docs";
import { marketingConfig } from "@/config/marketing";
import { siteConfig } from "@/config/site";
import { useScroll } from "@/hooks/use-scroll";
import { cn } from "@/lib/utils";
import useScroll from "@/hooks/use-scroll";
import { useSigninModal } from "@/hooks/use-signin-modal";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { DocsSearch } from "@/components/docs/search";
import { Icons } from "@/components/shared/icons";
import MaxWidthWrapper from "@/components/shared/max-width-wrapper";

import { UserAccountNav } from "./user-account-nav";

Expand All @@ -26,8 +27,8 @@ interface NavBarProps {

export function NavBar({ scroll = false }: NavBarProps) {
const scrolled = useScroll(50);
const signInModal = useSigninModal();
const { data: session, status } = useSession();
const { setShowSignInModal } = useContext(ModalContext);

const selectedLayout = useSelectedLayoutSegment();
const dashBoard = selectedLayout === "dashboard";
Expand Down Expand Up @@ -124,7 +125,7 @@ export function NavBar({ scroll = false }: NavBarProps) {
variant="default"
size="sm"
rounded="full"
onClick={signInModal.onOpen}
onClick={() => setShowSignInModal(true)}
>
<span>Sign In</span>
<Icons.arrowRight className="size-4" />
Expand Down
19 changes: 0 additions & 19 deletions components/modal-provider.tsx

This file was deleted.

26 changes: 26 additions & 0 deletions components/modals/providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"use client";

import { createContext, Dispatch, ReactNode, SetStateAction } from "react";

import { useSignInModal } from "@/components/modals//sign-in-modal";

export const ModalContext = createContext<{
setShowSignInModal: Dispatch<SetStateAction<boolean>>;
}>({
setShowSignInModal: () => {},
});

export default function ModalProvider({ children }: { children: ReactNode }) {
const { SignInModal, setShowSignInModal } = useSignInModal();

return (
<ModalContext.Provider
value={{
setShowSignInModal,
}}
>
<SignInModal />
{children}
</ModalContext.Provider>
);
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
"use client";

import { useState } from "react";
import { signIn } from "next-auth/react";
import {
Dispatch,
SetStateAction,
useCallback,
useMemo,
useState,
} from "react";

import { Icons } from "@/components/shared/icons";
import { Modal } from "@/components/shared/modal";
import { Button } from "@/components/ui/button";
import { Modal } from "@/components/ui/modal";
import { siteConfig } from "@/config/site";
import { useSigninModal } from "@/hooks/use-signin-modal";
import { signIn } from "next-auth/react";

export const SignInModal = () => {
const signInModal = useSigninModal();
function SignInModal({
showSignInModal,
setShowSignInModal,
}: {
showSignInModal: boolean;
setShowSignInModal: Dispatch<SetStateAction<boolean>>;
}) {
const [signInClicked, setSignInClicked] = useState(false);

return (
<Modal showModal={signInModal.isOpen} setShowModal={signInModal.onClose}>
<Modal showModal={showSignInModal} setShowModal={setShowSignInModal}>
<div className="w-full">
<div className="flex flex-col items-center justify-center space-y-3 border-b bg-background px-4 py-6 pt-8 text-center md:px-16">
<a href={siteConfig.url}>
Expand All @@ -34,10 +42,9 @@ export const SignInModal = () => {
onClick={() => {
setSignInClicked(true);
signIn("google", { redirect: false }).then(() =>
// TODO: fix this without setTimeOut(), modal closes too quickly. Idea: update value before redirect
setTimeout(() => {
signInModal.onClose();
}, 1000)
setShowSignInModal(false);
}, 400),
);
}}
>
Expand All @@ -52,4 +59,25 @@ export const SignInModal = () => {
</div>
</Modal>
);
};
}

export function useSignInModal() {
const [showSignInModal, setShowSignInModal] = useState(false);

const SignInModalCallback = useCallback(() => {
return (
<SignInModal
showSignInModal={showSignInModal}
setShowSignInModal={setShowSignInModal}
/>
);
}, [showSignInModal, setShowSignInModal]);

return useMemo(
() => ({
setShowSignInModal,
SignInModal: SignInModalCallback,
}),
[setShowSignInModal, SignInModalCallback],
);
}
13 changes: 6 additions & 7 deletions components/pricing-cards.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
"use client";

import { useState } from "react";
import { useContext, useState } from "react";
import Link from "next/link";
import { UserSubscriptionPlan } from "@/types";

import { SubscriptionPlan } from "@/types/index";
import { pricingData } from "@/config/subscriptions";
import { cn } from "@/lib/utils";
import { useSigninModal } from "@/hooks/use-signin-modal";
import { Button, buttonVariants } from "@/components/ui/button";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { BillingFormButton } from "@/components/forms/billing-form-button";
import { ModalContext } from "@/components/modals/providers";
import { HeaderSection } from "@/components/shared/header-section";
import { Icons } from "@/components/shared/icons";

import { SubscriptionPlan } from "../types/index";
import MaxWidthWrapper from "./shared/max-width-wrapper";
import MaxWidthWrapper from "@/components/shared/max-width-wrapper";

interface PricingCardsProps {
userId?: string;
Expand All @@ -27,7 +26,7 @@ export function PricingCards({ userId, subscriptionPlan }: PricingCardsProps) {
? true
: false;
const [isYearly, setIsYearly] = useState<boolean>(!!isYearlyDefault);
const signInModal = useSigninModal();
const { setShowSignInModal } = useContext(ModalContext);

const toggleBilling = () => {
setIsYearly(!isYearly);
Expand Down Expand Up @@ -127,7 +126,7 @@ export function PricingCards({ userId, subscriptionPlan }: PricingCardsProps) {
: "outline"
}
rounded="full"
onClick={signInModal.onOpen}
onClick={() => setShowSignInModal(true)}
>
Sign in
</Button>
Expand Down
51 changes: 0 additions & 51 deletions components/shared/modal.tsx

This file was deleted.

99 changes: 99 additions & 0 deletions components/ui/modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"use client";

import { Dispatch, SetStateAction } from "react";
// import { useRouter } from "next/router";
import { Drawer } from "vaul";

import { Dialog, DialogContent } from "@/components/ui/dialog";
import { useMediaQuery } from "@/hooks/use-media-query";
import { cn } from "@/lib/utils";

interface ModalProps {
children: React.ReactNode;
className?: string;
showModal?: boolean;
setShowModal?: Dispatch<SetStateAction<boolean>>;
onClose?: () => void;
desktopOnly?: boolean;
preventDefaultClose?: boolean;
}

export function Modal({
children,
className,
showModal,
setShowModal,
onClose,
desktopOnly,
preventDefaultClose,
}: ModalProps) {
// const router = useRouter();

const closeModal = ({ dragged }: { dragged?: boolean } = {}) => {
if (preventDefaultClose && !dragged) {
return;
}
// fire onClose event if provided
onClose && onClose();

// if setShowModal is defined, use it to close modal
if (setShowModal) {
setShowModal(false);
}
// else, this is intercepting route @modal
// else {
// router.back();
// }
};
const { isMobile } = useMediaQuery();

if (isMobile && !desktopOnly) {
return (
<Drawer.Root
open={setShowModal ? showModal : true}
onOpenChange={(open) => {
if (!open) {
closeModal({ dragged: true });
}
}}
>
<Drawer.Overlay className="fixed inset-0 z-40 bg-background/80 backdrop-blur-sm" />
<Drawer.Portal>
<Drawer.Content
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 overflow-hidden rounded-t-[10px] border bg-background",
className,
)}
>
<div className="sticky top-0 z-20 flex w-full items-center justify-center bg-inherit">
<div className="my-3 h-1.5 w-16 rounded-full bg-muted-foreground/20" />
</div>
{children}
</Drawer.Content>
<Drawer.Overlay />
</Drawer.Portal>
</Drawer.Root>
);
}
return (
<Dialog
open={setShowModal ? showModal : true}
onOpenChange={(open) => {
if (!open) {
closeModal();
}
}}
>
<DialogContent
onOpenAutoFocus={(e) => e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}
className={cn(
"overflow-hidden p-0 md:max-w-md md:rounded-2xl md:border",
className,
)}
>
{children}
</DialogContent>
</Dialog>
);
}
Loading

0 comments on commit db932c9

Please sign in to comment.