mirror of
https://github.com/MAGICGrants/campaign-site.git
synced 2026-01-09 20:38:02 -05:00
* Apply OpenSats UI enhancements * Add register modal and some UI fixes * Add login modal * Add reset password button * Use @t3-oss/env-nextjs for env variables * Email verification without keycloak UI * Password reset without keycloak UI * Add "My donations" page with one-time stripe donations list * Display crypto donations in "My donations" page * Donation form fixes and improvements * Display recurring annual fiat donations * Include keycloak realm export file and remove hardcoded client values * fix: correctly handle btcpay webhooks and fix donationList query * feat: add membership modal and implement membership payment using btcpay * feat: add procedure for membership purchases with stripe and use db as single source of truth for donations * feat: use webhooks to update stripe donation/membership status * feat: memberships list page and fixes * feat: db schema changes and webhook fixes * feat: re-add "donate" and add "get annual membership" buttons to project page * feat: open register modal when clicking membership button while logged out * feat: replace "Get Membership" button with "My Memberships" button when user already has a membership for that project * feat: multiple funds support * deps: bump axios * feat: add different color schemes for each fund and some fixes * feat: add home page * feat: add missing titles and responsiveness improvements * chore: add prod workflow file and compose file * chore(deploy workflow): set environment name * chore(Dockerfile): add necessary lines for prisma * chore: make it skip env validation on build * fix: prevent donation amounts from being fetched from db during build * chore(nginx.conf): remove copy-paste junk * chore(docker compose): correctly set APP_URL env * feat: replace Sendgrid with SES * deps: audit fix * chore(deploy.yml): remove unecessary env * fix: correctly manage client and server env * fix(trpc.submitApplication): get recipient emails from server side env * fix(Dockerfile): define NEXT_PUBLIC_ env on build * chore(trpc): make it log any errors * chore(trpc): improve displaying of errors * chore(trpc): improve displaying of errors * fix: buggy link buttons * feat: use single btcpay store * feat: show form 8283 info in donation form and handle tax deductible donations * feat: have only one privacy and terms page for the entire site * feat: support many social links * feat: add funding required endpoint (wip) * feat: get rates using btcpay api and small refactor * deps: audit fix * fix: correctly handle payment methods on InvoiceSettled event * fix: make index on Donation.btcPayInvoiceId * feat(funding-required): improve asset parameter response * feat(funding-required): add project_status param * feat(funding-required): add fund param * feat(funding-required): implement caching * fix(funding-required): minor fixes * feat(funding-required): add remaining_amount_<currency> fields and fixes * chore: include all services in docker-compose.dev.yml and update .env.example * feat: move terms and privacy links to footer * fix: address font not always loading bug * feat: use fund logos as header image * feat: donation confirmation email * fix: use correct stripe client for each fund on webhooks * feat: add account settings page with change password form * feat: add email change form to settings page * fix: address wrong btcpay invoice url redirect * chore: email change request debug * fix(api): better handle user attributes * feat: ui improvements * feat: add btcpay invoice item description * chore(nginx): api rate limit * feat: remove typing component from fund landing pages * feat: implement refresh token rotation using keycloak * refactor: have gross and net amounts for donations * feat: invalidate user sessions on password/email change * fix: make "Create an account" button work on donate/membership modals * refactor: project props * fix(utils.md): correctly load md project attributes * chore(prisma): make composite unique constraint for fundSlug and projectSlug on ProjectAddresses * chore: mark example project as not funded * fix(utils.md): serialization error * chore(funding-required): btcpay invoice payment methods debug * fix(funding-required): get bitcoin address from correct payment method * fix(funding-required): correctly handle project_status ANY filter * fix(btcpay webhook handler): correctly handle payment methods on InvoicePaymentSettled * chore(docker-compose.yml): expose nginx port 80 * fix(funding-required): correctly concat project url * feat: ui improvements for smaller screens * fix(btcpay webhook handler): correctly get payment method amount on InvoiceSettled * fix(btcpay webhook handler): respond with 200 immediately if there is no metadata * chore(funding-required): debugging * chore(funding-required): debugging * chore(funding-required): debugging * fix(Dockerfile): define BUILD_MODE as arg instead of env to make it blank at runtime * fix: correctly pass current and goal values to project card progress * fix(funding-required): set high monitoring time for static address invoice * fix: correctly handle refresh token expiration on the ui * feat: ui improvements * chore: update README * chore: update README * Initial site text * fix: colors * chore: mention funds accordingly in texts * chore: update realm-export.json * chore: rename docker compose files * Update emails * Form updates * Remove unused pages and page improvements * feat: allow editing navbar links for each fund * Cleanup and Firo projects * chore(deploy.yml): change deploy branch to master * fix(auth): use fetch instead of axios when fetching refresh token due to edge runtime compatibility * fix: keep empty project folders * Fix code scanning alert no. 20: DOM text reinterpreted as HTML Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * chore: sanitize md file paths * Text and link updates --------- Co-authored-by: Artur N <arturnunespe@gmail.com> Co-authored-by: Justin Ehrenhofer <12520755+SamsungGalaxyPlayer@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
166 lines
6.0 KiB
TypeScript
166 lines
6.0 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { signOut, useSession } from 'next-auth/react'
|
|
import { useRouter } from 'next/router'
|
|
|
|
import Link from './CustomLink'
|
|
import MobileNav from './MobileNav'
|
|
import { fundHeaderNavLinks } from '../data/headerNavLinks'
|
|
import MagicLogo from './MagicLogo'
|
|
import { Dialog, DialogContent, DialogTrigger } from './ui/dialog'
|
|
import { Button } from './ui/button'
|
|
import RegisterFormModal from './RegisterFormModal'
|
|
import LoginFormModal from './LoginFormModal'
|
|
import PasswordResetFormModal from './PasswordResetFormModal'
|
|
import { Avatar, AvatarFallback } from './ui/avatar'
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from './ui/dropdown-menu'
|
|
import { useFundSlug } from '../utils/use-fund-slug'
|
|
import CustomLink from './CustomLink'
|
|
import { funds } from '../utils/funds'
|
|
import MoneroLogo from './MoneroLogo'
|
|
import FiroLogo from './FiroLogo'
|
|
import PrivacyGuidesLogo from './PrivacyGuidesLogo'
|
|
|
|
const Header = () => {
|
|
const [registerIsOpen, setRegisterIsOpen] = useState(false)
|
|
const [loginIsOpen, setLoginIsOpen] = useState(false)
|
|
const [passwordResetIsOpen, setPasswordResetIsOpen] = useState(false)
|
|
const router = useRouter()
|
|
const session = useSession()
|
|
const fundSlug = useFundSlug()
|
|
|
|
useEffect(() => {
|
|
if (router.query.loginEmail) {
|
|
setLoginIsOpen(true)
|
|
}
|
|
}, [router.query.loginEmail])
|
|
|
|
const fund = fundSlug ? funds[fundSlug] : null
|
|
|
|
return (
|
|
<header className="flex items-center justify-between py-10">
|
|
<div>
|
|
<Link
|
|
href={fundSlug ? `/${fundSlug}` : '/'}
|
|
aria-label="Home"
|
|
className="flex items-center mr-3 gap-4"
|
|
>
|
|
{!fundSlug && <MagicLogo className="w-12 h-12" />}
|
|
{fundSlug === 'monero' && <MoneroLogo className="w-12 h-12" />}
|
|
{fundSlug === 'firo' && <FiroLogo className="w-12 h-12" />}
|
|
{fundSlug === 'privacyguides' && <PrivacyGuidesLogo className="w-12 h-12" />}
|
|
{fundSlug === 'general' && <MagicLogo className="w-12 h-12" />}
|
|
|
|
<span className="text-foreground text-lg font-bold hidden sm:block">
|
|
{fund ? fund.title : 'MAGIC Grants'}
|
|
</span>
|
|
</Link>
|
|
</div>
|
|
|
|
<div className="flex gap-2 items-center text-base leading-5">
|
|
{!!fund &&
|
|
fundHeaderNavLinks[fund.slug].map((link) => (
|
|
<CustomLink
|
|
key={link.title}
|
|
href={`/${fundSlug}/${link.href}`}
|
|
className={
|
|
link.isButton
|
|
? 'rounded border border-primary bg-transparent px-4 py-2 font-semibold text-primary hover:border-transparent hover:bg-primary hover:text-white'
|
|
: 'hidden p-1 font-medium text-gray-900 sm:p-4 md:inline-block'
|
|
}
|
|
>
|
|
{link.title}
|
|
</CustomLink>
|
|
))}
|
|
|
|
{!!fund && session.status !== 'authenticated' && (
|
|
<>
|
|
<Dialog open={loginIsOpen} onOpenChange={setLoginIsOpen}>
|
|
<DialogTrigger asChild>
|
|
<Button variant="outline" className="w-18 block sm:hidden" size="sm">
|
|
Login
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogTrigger asChild>
|
|
<Button variant="outline" className="w-24 hidden sm:block">
|
|
Login
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<LoginFormModal
|
|
close={() => setLoginIsOpen(false)}
|
|
openRegisterModal={() => setRegisterIsOpen(true)}
|
|
openPasswordResetModal={() => setPasswordResetIsOpen(true)}
|
|
/>
|
|
</DialogContent>
|
|
</Dialog>
|
|
|
|
<Dialog open={registerIsOpen} onOpenChange={setRegisterIsOpen}>
|
|
<DialogTrigger asChild>
|
|
<Button className="w-18 block sm:hidden" size="sm">
|
|
Register
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogTrigger asChild>
|
|
<Button className="w-24 hidden sm:block">Register</Button>
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<RegisterFormModal
|
|
close={() => setRegisterIsOpen(false)}
|
|
openLoginModal={() => setLoginIsOpen(true)}
|
|
/>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</>
|
|
)}
|
|
|
|
{/* <ThemeSwitch /> */}
|
|
|
|
{!!fund && session.status === 'authenticated' && (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger>
|
|
<Avatar>
|
|
<AvatarFallback>
|
|
{session.data.user?.email?.slice(0, 2).toUpperCase()}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent>
|
|
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<CustomLink href={`/${fundSlug}/account/my-donations`} className="text-foreground">
|
|
<DropdownMenuItem>My Donations</DropdownMenuItem>
|
|
</CustomLink>
|
|
<CustomLink href={`/${fundSlug}/account/my-memberships`} className="text-foreground">
|
|
<DropdownMenuItem>My Memberships</DropdownMenuItem>
|
|
</CustomLink>
|
|
<CustomLink href={`/${fundSlug}/account/settings`} className="text-foreground">
|
|
<DropdownMenuItem>Settings</DropdownMenuItem>
|
|
</CustomLink>
|
|
<DropdownMenuItem onClick={() => signOut({ callbackUrl: `/${fundSlug}` })}>
|
|
Logout
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
)}
|
|
|
|
{!!fundSlug && <MobileNav />}
|
|
</div>
|
|
|
|
<Dialog open={passwordResetIsOpen} onOpenChange={setPasswordResetIsOpen}>
|
|
<DialogContent>
|
|
<PasswordResetFormModal close={() => setPasswordResetIsOpen(false)} />
|
|
</DialogContent>
|
|
</Dialog>
|
|
</header>
|
|
)
|
|
}
|
|
|
|
export default Header
|