Skip to content

Commit

Permalink
Merge pull request #31 from j-h-scheufen/onboarding-flag
Browse files Browse the repository at this point in the history
Onboarding flag
  • Loading branch information
j-h-scheufen authored Oct 3, 2024
2 parents 6b878f0 + 1571480 commit d657880
Show file tree
Hide file tree
Showing 20 changed files with 1,280 additions and 676 deletions.
5 changes: 4 additions & 1 deletion packages/app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ yarn-error.log*
next-env.d.ts

# build artifacts
/generated
/generated

# performance metrics
.million
3 changes: 0 additions & 3 deletions packages/app/app/_providers/jotai.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ const CurrentUserProvider = ({ children }: PropsWithChildren) => {
[triggerCurrentUserIdAtom, session?.user?.id],
] as const);

// useEffect(() => {
// if (session && (!triggerId || triggerId !== session.user?.id)) setTriggerId(session?.user?.id);
// }, [session, triggerId, setTriggerId]);
return children;
};

Expand Down
228 changes: 116 additions & 112 deletions packages/app/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { PATHS } from '@/config/constants';
import { currentUserAtom, currentUserAvatarUrlAtom } from '@/hooks/state/currentUser';
import useAuth from '@/hooks/useAuth';
import { getUserDisplayName } from '@/utils';
import OnboardingModal from './OnboardingModal';
import { ThemeSwitch } from './ThemeSwitch';

const Navbar: React.FC = () => {
Expand All @@ -37,120 +38,123 @@ const Navbar: React.FC = () => {
const isPathDao = pathname === PATHS.dao;

return (
<NextUINavbar
maxWidth="md"
position="sticky"
shouldHideOnScroll={false}
isMenuOpen={isMenuOpen}
onMenuOpenChange={setIsMenuOpen}
classNames={{
item: ['data-[active=true]:text-primary-400', 'data-[active=true]:dark:text-primary'],
menuItem: ['data-[active=true]:text-primary-400', 'data-[active=true]:dark:text-primary'],
}}
>
<NavbarContent>
<NavbarMenuToggle aria-label={isMenuOpen ? 'Close menu' : 'Open menu'} className="sm:hidden" />
<NavbarBrand>
<NextLink className="flex items-center justify-start gap-1" href="/">
<h1 className="text-2xl font-bold">Quilombo</h1>
</NextLink>
</NavbarBrand>
</NavbarContent>
<>
<NextUINavbar
maxWidth="md"
position="sticky"
shouldHideOnScroll={false}
isMenuOpen={isMenuOpen}
onMenuOpenChange={setIsMenuOpen}
classNames={{
item: ['data-[active=true]:text-primary-400', 'data-[active=true]:dark:text-primary'],
menuItem: ['data-[active=true]:text-primary-400', 'data-[active=true]:dark:text-primary'],
}}
>
<NavbarContent>
<NavbarMenuToggle aria-label={isMenuOpen ? 'Close menu' : 'Open menu'} className="sm:hidden" />
<NavbarBrand>
<NextLink className="flex items-center justify-start gap-1" href="/">
<h1 className="text-2xl font-bold">Quilombo</h1>
</NextLink>
</NavbarBrand>
</NavbarContent>

<NavbarContent className="hidden sm:flex gap-4" justify="center">
<NavbarItem isActive={isPathDashboard}>
<Link color="foreground" href={PATHS.search} size="lg" className="text-inherit">
Search
</Link>
</NavbarItem>
<NavbarItem isActive={isPathAxe}>
<Link color="foreground" href={PATHS.axe} size="lg" className="text-inherit">
Axé
</Link>
</NavbarItem>
<NavbarItem isActive={isPathDao}>
<Link color="foreground" href={PATHS.dao} size="lg" className="text-inherit">
Organization
</Link>
</NavbarItem>
</NavbarContent>
<NavbarContent className="hidden sm:flex gap-4" justify="center">
<NavbarItem isActive={isPathDashboard}>
<Link color="foreground" href={PATHS.search} size="lg" className="text-inherit">
Search
</Link>
</NavbarItem>
<NavbarItem isActive={isPathAxe}>
<Link color="foreground" href={PATHS.axe} size="lg" className="text-inherit">
Axé
</Link>
</NavbarItem>
<NavbarItem isActive={isPathDao}>
<Link color="foreground" href={PATHS.dao} size="lg" className="text-inherit">
Organization
</Link>
</NavbarItem>
</NavbarContent>

<NavbarContent as="div" justify="end">
<ThemeSwitch />
{session && !!user && (
<Dropdown placement="bottom-end">
<DropdownTrigger>
<Avatar
isBordered
as="button"
className="transition-transform"
color="primary"
name={user.name || undefined}
size="sm"
src={avatarUrl}
/>
</DropdownTrigger>
<DropdownMenu aria-label="Profile Actions" variant="flat">
<DropdownItem key="profile" className="h-14 gap-2">
<p className="font-semibold">Signed in as</p>
<p className="font-semibold">{getUserDisplayName(user)}</p>
</DropdownItem>
<DropdownItem key="my-profile" href={PATHS.profile}>
My Profile
</DropdownItem>
<DropdownItem
key="my-group"
href={`${PATHS.groups}/${user.groupId || ''}`}
className={!!user.groupId ? '' : 'hidden'}
>
My Group
</DropdownItem>
<DropdownItem key="admin" href={PATHS.admin} className={user.isGlobalAdmin ? '' : 'hidden'}>
Admin
</DropdownItem>
<DropdownItem key="logout" color="danger" onPress={logout}>
Log out
</DropdownItem>
</DropdownMenu>
</Dropdown>
)}
</NavbarContent>
<NavbarMenu>
<NavbarMenuItem isActive={isPathDashboard}>
<Link
color="foreground"
className="w-full text-inherit"
href={PATHS.search}
size="lg"
onPress={() => setIsMenuOpen(false)}
>
Search
</Link>
</NavbarMenuItem>
<NavbarMenuItem isActive={isPathAxe}>
<Link
color="foreground"
className="w-full text-inherit"
href={PATHS.axe}
size="lg"
onPress={() => setIsMenuOpen(false)}
>
Axé
</Link>
</NavbarMenuItem>
<NavbarMenuItem isActive={isPathDao}>
<Link
color="foreground"
className="w-full text-inherit"
href={PATHS.dao}
size="lg"
onPress={() => setIsMenuOpen(false)}
>
Organization
</Link>
</NavbarMenuItem>
</NavbarMenu>
</NextUINavbar>
<NavbarContent as="div" justify="end">
<ThemeSwitch />
{session && !!user && (
<Dropdown placement="bottom-end">
<DropdownTrigger>
<Avatar
isBordered
as="button"
className="transition-transform"
color="primary"
name={user.name || undefined}
size="sm"
src={avatarUrl}
/>
</DropdownTrigger>
<DropdownMenu aria-label="Profile Actions" variant="flat">
<DropdownItem key="profile" className="h-14 gap-2">
<p className="font-semibold">Signed in as</p>
<p className="font-semibold">{getUserDisplayName(user)}</p>
</DropdownItem>
<DropdownItem key="my-profile" href={PATHS.profile}>
My Profile
</DropdownItem>
<DropdownItem
key="my-group"
href={`${PATHS.groups}/${user.groupId || ''}`}
className={!!user.groupId ? '' : 'hidden'}
>
My Group
</DropdownItem>
<DropdownItem key="admin" href={PATHS.admin} className={user.isGlobalAdmin ? '' : 'hidden'}>
Admin
</DropdownItem>
<DropdownItem key="logout" color="danger" onPress={logout}>
Log out
</DropdownItem>
</DropdownMenu>
</Dropdown>
)}
</NavbarContent>
<NavbarMenu>
<NavbarMenuItem isActive={isPathDashboard}>
<Link
color="foreground"
className="w-full text-inherit"
href={PATHS.search}
size="lg"
onPress={() => setIsMenuOpen(false)}
>
Search
</Link>
</NavbarMenuItem>
<NavbarMenuItem isActive={isPathAxe}>
<Link
color="foreground"
className="w-full text-inherit"
href={PATHS.axe}
size="lg"
onPress={() => setIsMenuOpen(false)}
>
Axé
</Link>
</NavbarMenuItem>
<NavbarMenuItem isActive={isPathDao}>
<Link
color="foreground"
className="w-full text-inherit"
href={PATHS.dao}
size="lg"
onPress={() => setIsMenuOpen(false)}
>
Organization
</Link>
</NavbarMenuItem>
</NavbarMenu>
</NextUINavbar>
<OnboardingModal />
</>
);
};

Expand Down
75 changes: 75 additions & 0 deletions packages/app/components/OnboardingModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use client';

import { Button } from '@nextui-org/button';
import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, useDisclosure } from '@nextui-org/modal';
import { useAtomValue } from 'jotai';
import { useCallback, useEffect } from 'react';

import { PATHS } from '@/config/constants';
import { currentUserAtom } from '@/hooks/state/currentUser';
import { getCookie, setCookie } from 'cookies-next';
import { useRouter } from 'next/navigation';

/**
* This modal automatically opens on first login (and page reload) if the user hasn't filled out
* at least a name or nickname. It sets a cookie that expires after 24 hours to prevent the modal from
* showing up again. If the user still hasn't completed the described fields after that
* time, the modal would be displayed again.
*/
const OnboardingModal = () => {
const { isOpen, onOpen, onOpenChange } = useDisclosure();
const router = useRouter();
const { data: user } = useAtomValue(currentUserAtom);

useEffect(() => {
if (user && !user.name && !user.nickname) {
const skipOnboarding = getCookie('quilombo.skipOnboarding');
if (skipOnboarding === 'true') return;
onOpen();
}
}, [user, onOpen]);

const handleClose = useCallback(
async (target: string) => {
setCookie('quilombo.skipOnboarding', true, {
expires: new Date(Date.now() + 1000 * 60 * 60 * 24), // we give the user 24 hrs before reminding again
});

router.push(target);
},
[router],
);

return (
<Modal isOpen={isOpen} onOpenChange={onOpenChange} isDismissable={false} isKeyboardDismissDisabled={true}>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">Hi There! Que bom te ver.</ModalHeader>
<ModalBody>
<p>
Nice to meet you! You probably just signed up or haven&apos;t filled out some basic information, yet, so
we don&apos;t know how to address you.
</p>
<p>Do you have a nickname? Are you a mestre or mestra ... or initiante? Which group do you belong to?</p>
<p>
Head over to &apos;<b>My Profile</b>&apos; and let the community know who you are. You can also do this
later at any time by going to &apos;<b>My Profile</b>&apos; in the user menu on the top right.
</p>
</ModalBody>
<ModalFooter>
<Button color="secondary" variant="light" onPress={() => handleClose(PATHS.search).then(onClose)}>
Browse around
</Button>
<Button color="primary" onPress={() => handleClose(`${PATHS.profile}/edit`).then(onClose)}>
Take me to My Profile
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
);
};

export default OnboardingModal;
Loading

0 comments on commit d657880

Please sign in to comment.