Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- template/app/migrations/20241030143842_checkout_session_id/migration.sql
+++ opensaas-sh/app/migrations/20241030143842_checkout_session_id/migration.sql
@@ -0,0 +1,8 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `checkoutSessionId` on the `User` table. All the data in the column will be lost.
+
+*/
+-- AlterTable
+ALTER TABLE "User" DROP COLUMN "checkoutSessionId";
72 changes: 72 additions & 0 deletions opensaas-sh/app_diff/src/client/components/NavBar/NavBar.tsx.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
--- template/app/src/client/components/NavBar/NavBar.tsx
+++ opensaas-sh/app/src/client/components/NavBar/NavBar.tsx
@@ -31,6 +31,7 @@
!isLandingPage,
})}
>
+ {isLandingPage && <Announcement />}
<nav className='flex items-center justify-between p-6 lg:px-8' aria-label='Global'>
<div className='flex items-center lg:flex-1'>
<Link
@@ -38,9 +39,7 @@
className='flex items-center -m-1.5 p-1.5 text-gray-900 duration-300 ease-in-out hover:text-yellow-500'
>
<NavLogo />
- {isLandingPage && (
- <span className='ml-2 text-sm font-semibold leading-6 dark:text-white'>Your Saas</span>
- )}
+ {isLandingPage && <span className='ml-2 text-sm font-semibold leading-6 dark:text-white'>Open Saas</span>}
</Link>
</div>
<div className='flex lg:hidden'>
@@ -60,9 +59,9 @@
</ul>
{isUserLoading ? null : !user ? (
<Link to='/login' className='text-sm font-semibold leading-6 ml-3'>
- <div className='flex items-center duration-300 ease-in-out text-gray-900 hover:text-yellow-500 dark:text-white'>
- Log in <BiLogIn size='1.1rem' className='ml-1 mt-[0.1rem]' />
- </div>
+ <div className='flex justify-end items-center duration-300 ease-in-out text-gray-900 hover:text-yellow-500 dark:text-white test-sm'>
+ Try the demo App <BiLogIn size='1.1rem' className='ml-1' />
+ </div>
</Link>
) : (
<div className='ml-3'>
@@ -95,7 +94,7 @@
{isUserLoading ? null : !user ? (
<Link to='/login'>
<div className='flex justify-end items-center duration-300 ease-in-out text-gray-900 hover:text-yellow-500 dark:text-white'>
- Log in <BiLogIn size='1.1rem' className='ml-1' />
+ Try the Demo App{' '} <BiLogIn size='1.1rem' className='ml-1' />
</div>
</Link>
) : (
@@ -137,3 +136,27 @@
);
});
}
+
+const ContestURL =
+ 'https://docs.opensaas.sh/blog/';
+
+function Announcement() {
+ return (
+ <div className='flex justify-center items-center gap-3 p-3 w-full bg-gradient-to-r from-[#d946ef] to-[#fc0] font-semibold text-white text-center z-49'>
+ <p onClick={() => window.open(ContestURL, '_blank')} className='hidden lg:block cursor-pointer hover:opacity-90 hover:drop-shadow'>🍪 THE MOST ANNOYING COOKIE BANNER EVER HACKATHON 🤬</p>
+ <div className='hidden lg:block self-stretch w-0.5 bg-white'></div>
+ <div
+ onClick={() => window.open(ContestURL, '_blank')}
+ className='hidden lg:block cursor-pointer rounded-full bg-neutral-700 px-2.5 py-1 text-xs hover:bg-neutral-600 tracking-wider'
+ >
+ Enter here and win prizes! →
+ </div>
+ <div
+ onClick={() => window.open(ContestURL, '_blank')}
+ className='lg:hidden cursor-pointer rounded-full bg-neutral-700 px-2.5 py-1 text-xs hover:bg-neutral-600 tracking-wider'
+ >
+ 🍪 The Most Annoying Cookie Banner Contest! 🤬 →
+ </div>
+ </div>
+ );
+}
\ No newline at end of file
88 changes: 0 additions & 88 deletions opensaas-sh/app_diff/src/landing-page/components/Header.tsx.diff

This file was deleted.

10 changes: 5 additions & 5 deletions opensaas-sh/app_diff/src/landing-page/contentSections.ts.diff
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
-import { routes } from 'wasp/client/router';
+import { DocsUrl, BlogUrl, GithubUrl } from '../shared/common';

export const navigation = [
{ name: 'Features', href: '#features' },
- { name: 'Pricing', href: routes.PricingPageRoute.build() },
{ name: 'Documentation', href: DocsUrl },
{ name: 'Blog', href: BlogUrl },
export const landingPageNavigationItems = [
{ name: 'Features', to: '#features' },
- { name: 'Pricing', to: routes.PricingPageRoute.to },
{ name: 'Documentation', to: DocsUrl },
{ name: 'Blog', to: BlogUrl },
];
export const features = [
{
Expand Down
14 changes: 10 additions & 4 deletions template/app/src/client/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useAuth } from 'wasp/client/auth';
import { updateCurrentUser } from 'wasp/client/operations';
import './Main.css';
import AppNavBar from './components/AppNavBar';
import NavBar from './components/NavBar/NavBar';
import { appNavigationItems } from './components/NavBar/contentSections';
import { landingPageNavigationItems } from '../landing-page/contentSections';
import CookieConsentBanner from './components/cookie-consent/Banner';
import { useMemo, useEffect, ReactNode } from 'react';
import { useMemo, useEffect } from 'react';
import { Outlet, useLocation } from 'react-router-dom';
import { useIsLandingPage } from './hooks/useIsLandingPage';

/**
* use this component to wrap all child components
Expand All @@ -13,9 +16,10 @@ import { Outlet, useLocation } from 'react-router-dom';
export default function App() {
const location = useLocation();
const { data: user } = useAuth();
const isLandingPage = useIsLandingPage();

const shouldDisplayAppNavBar = useMemo(() => {
return location.pathname !== '/' && location.pathname !== '/login' && location.pathname !== '/signup';
return location.pathname !== '/login' && location.pathname !== '/signup';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid hard-coding values, you could use routes.LoginRoute.build() and routes.SignupRoute.build() to get the routes :)

}, [location]);

const isAdminDashboard = useMemo(() => {
Expand Down Expand Up @@ -49,7 +53,9 @@ export default function App() {
<Outlet />
) : (
<>
{shouldDisplayAppNavBar && <AppNavBar />}
{shouldDisplayAppNavBar && (
<NavBar navigation={isLandingPage ? landingPageNavigationItems : appNavigationItems} />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing you could do here is extract the ternary expresison:

const navigationItems = isLandingPage ? landingPageNavigationItems : appNavigationItems;
...
<NavBar navigation={navigationItems} />

That being said, it looks to me that the navigation prop should be named navigationItems since we are calling all the vars that way xNavigationItems.

)}
<div className='mx-auto max-w-7xl sm:px-6 lg:px-8'>
<Outlet />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
import { Link, routes } from 'wasp/client/router';
import { Link } from 'react-router-dom';
import { useAuth } from 'wasp/client/auth';
import { useState } from 'react';
import { useState, Dispatch, SetStateAction } from 'react';
import { Dialog } from '@headlessui/react';
import { BiLogIn } from 'react-icons/bi';
import { AiFillCloseCircle } from 'react-icons/ai';
import { HiBars3 } from 'react-icons/hi2';
import logo from '../static/logo.png';
import DropdownUser from '../../user/DropdownUser';
import { UserMenuItems } from '../../user/UserMenuItems';
import { DocsUrl, BlogUrl } from '../../shared/common';
import DarkModeSwitcher from './DarkModeSwitcher';
import logo from '../../static/logo.png';
import DropdownUser from '../../../user/DropdownUser';
import { UserMenuItems } from '../../../user/UserMenuItems';
import DarkModeSwitcher from '../DarkModeSwitcher';
import { useIsLandingPage } from '../../hooks/useIsLandingPage';
import { cn } from '../../cn';

const navigation = [
{ name: 'AI Scheduler (Demo App)', href: routes.DemoAppRoute.build() },
{ name: 'File Upload (AWS S3)', href: routes.FileUploadRoute.build() },
{ name: 'Pricing', href: routes.PricingPageRoute.build() },
{ name: 'Documentation', href: DocsUrl },
{ name: 'Blog', href: BlogUrl },
];
interface NavigationItem {
name: string;
to: string;
}

const NavLogo = () => <img className='h-8 w-8' src={logo} alt='Your SaaS App' />;

export default function AppNavBar() {
export default function AppNavBar({ navigation }: { navigation: NavigationItem[] }) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd name the navigation prop as navigationItems so it matches the way we use it. navigation feels generic as opposed to navigationItems.

const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const isLandingPage = useIsLandingPage();

const { data: user, isLoading: isUserLoading } = useAuth();
return (
<header className='absolute inset-x-0 top-0 z-50 shadow sticky bg-white bg-opacity-50 backdrop-blur-lg backdrop-filter dark:border dark:border-gray-100/10 dark:bg-boxdark-2'>
<header
className={cn('absolute inset-x-0 top-0 z-50 dark:bg-boxdark-2', {
'shadow sticky bg-white bg-opacity-50 backdrop-blur-lg backdrop-filter dark:border dark:border-gray-100/10':
!isLandingPage,
})}
>
<nav className='flex items-center justify-between p-6 lg:px-8' aria-label='Global'>
<div className='flex lg:flex-1'>
<a href='/' className='-m-1.5 p-1.5'>
<img className='h-8 w-8' src={logo} alt='My SaaS App' />
</a>
<div className='flex items-center lg:flex-1'>
<Link
to='/'
className='flex items-center -m-1.5 p-1.5 text-gray-900 duration-300 ease-in-out hover:text-yellow-500'
>
<NavLogo />
{isLandingPage && (
<span className='ml-2 text-sm font-semibold leading-6 dark:text-white'>Your Saas</span>
)}
</Link>
</div>
<div className='flex lg:hidden'>
<button
Expand All @@ -43,30 +53,19 @@ export default function AppNavBar() {
<HiBars3 className='h-6 w-6' aria-hidden='true' />
</button>
</div>
<div className='hidden lg:flex lg:gap-x-12'>
{navigation.map((item) => (
<a
key={item.name}
href={item.href}
className='text-sm font-semibold leading-6 text-gray-900 duration-300 ease-in-out hover:text-yellow-500 dark:text-white'
>
{item.name}
</a>
))}
</div>
<div className='hidden lg:flex lg:gap-x-12'>{renderNavigationItems(navigation)}</div>
<div className='hidden lg:flex lg:flex-1 gap-3 justify-end items-center'>
<ul className='flex justify-center items-center gap-2 sm:gap-4'>
<DarkModeSwitcher />
</ul>

{isUserLoading ? null : !user ? (
<a href={!user ? routes.LoginRoute.build() : routes.AccountRoute.build()} className='text-sm font-semibold leading-6 ml-4'>
<Link to='/login' className='text-sm font-semibold leading-6 ml-3'>
<div className='flex items-center duration-300 ease-in-out text-gray-900 hover:text-yellow-500 dark:text-white'>
Log in <BiLogIn size='1.1rem' className='ml-1 mt-[0.1rem]' />
</div>
</a>
</Link>
) : (
<div className='ml-4'>
<div className='ml-3'>
<DropdownUser user={user} />
</div>
)}
Expand All @@ -76,10 +75,10 @@ export default function AppNavBar() {
<div className='fixed inset-0 z-50' />
<Dialog.Panel className='fixed inset-y-0 right-0 z-50 w-full overflow-y-auto bg-white dark:text-white dark:bg-boxdark px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-900/10'>
<div className='flex items-center justify-between'>
<a href='/' className='-m-1.5 p-1.5'>
<Link to='/' className='-m-1.5 p-1.5'>
<span className='sr-only'>Your SaaS</span>
<NavLogo />
</a>
</Link>
<button
type='button'
className='-m-2.5 rounded-md p-2.5 text-gray-700 dark:text-gray-50'
Expand All @@ -91,18 +90,7 @@ export default function AppNavBar() {
</div>
<div className='mt-6 flow-root'>
<div className='-my-6 divide-y divide-gray-500/10'>
<div className='space-y-2 py-6'>
{navigation.map((item) => (
<a
key={item.name}
href={item.href}
onClick={() => setMobileMenuOpen(false)}
className='-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 hover:bg-gray-50 dark:text-white hover:dark:bg-boxdark-2'
>
{item.name}
</a>
))}
</div>
<div className='space-y-2 py-6'>{renderNavigationItems(navigation, setMobileMenuOpen)}</div>
<div className='py-6'>
{isUserLoading ? null : !user ? (
<Link to='/login'>
Expand All @@ -124,3 +112,28 @@ export default function AppNavBar() {
</header>
);
}

function renderNavigationItems(
navigation: NavigationItem[],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
navigation: NavigationItem[],
navigationItems: NavigationItem[],

setMobileMenuOpen?: Dispatch<SetStateAction<boolean>>
) {
const menuStyles = cn({
'-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 hover:bg-gray-50 dark:text-white dark:hover:bg-boxdark-2':
!!setMobileMenuOpen,
'text-sm font-semibold leading-6 text-gray-900 duration-300 ease-in-out hover:text-yellow-500 dark:text-white':
!setMobileMenuOpen,
});

return navigation.map((item) => {
return (
<Link
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd maybe import both Link from wasp/client/router and react-router-dom and use them in different places.

  1. I'd use the import { Link as ReactRouterLink } from 'react-router-dom'; and <ReactRouterLink> component in places where we are having dynamic to prop (in this fn)
  2. I'd use the Wasp's Link elsewhere where we use the to prop explicitly - we get as much out of the type safe component as possible.

to={item.to}
key={item.name}
className={menuStyles}
onClick={setMobileMenuOpen && (() => setMobileMenuOpen(false))}
>
{item.name}
</Link>
);
});
}
Loading