Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement subscription payment for /create-profile #1412

Draft
wants to merge 62 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
cf22401
feat: add marketing pages
dominik-stumpf Jul 17, 2024
8b0aa82
chore: strip layout and Header
dominik-stumpf Jul 17, 2024
d37f5f3
feat: add GuilPassInvite
dominik-stumpf Jul 17, 2024
6a35625
feat: add GuildPassInvite
dominik-stumpf Jul 17, 2024
a1bf2fc
feat: add threejs
dominik-stumpf Jul 17, 2024
a28c323
chore: fine tune carousel
dominik-stumpf Jul 18, 2024
f069fc0
feat: add CarouselDotButton
dominik-stumpf Jul 18, 2024
24b3aa7
chore: rename hook
dominik-stumpf Jul 18, 2024
c347414
fix: update CarouselDotButton type
dominik-stumpf Jul 18, 2024
c70bcb1
chore: remove margin bottom from canvas
dominik-stumpf Jul 18, 2024
6672c59
chore: ignore unknown error
dominik-stumpf Jul 18, 2024
24cc8ce
chore: add tooltip provider to layout
dominik-stumpf Jul 18, 2024
f524ec3
chore: attempt to merge picker and checkout card
dominik-stumpf Jul 18, 2024
bb3ea34
fix: correctly update the picked pass
dominik-stumpf Jul 18, 2024
e522890
chore: finish picker view
dominik-stumpf Jul 18, 2024
d2f4854
chore: add bold to chosen pass
dominik-stumpf Jul 18, 2024
d67f701
feat: rename modals, add start profile
dominik-stumpf Jul 18, 2024
6a440f4
chore: resize icon, add input inside label
dominik-stumpf Jul 18, 2024
7b3d865
chore: add manual control over progression
dominik-stumpf Jul 18, 2024
7280818
chore: spacing fix
dominik-stumpf Jul 18, 2024
dad44b0
chore: adjust StartProfile spacing
dominik-stumpf Jul 18, 2024
5141206
chore(css): adjust to design
dominik-stumpf Jul 19, 2024
110435e
chore: change button to ghost
dominik-stumpf Jul 19, 2024
1792234
fix: disallow empty changes on toggle button
dominik-stumpf Jul 19, 2024
64e93e8
chore: change avatar bg
dominik-stumpf Jul 19, 2024
bdb073f
feat: add keyboard navigation
dominik-stumpf Jul 19, 2024
cf6ba5d
chore: update to external changes
dominik-stumpf Jul 19, 2024
6d7139d
Merge branch 'main' into profiles-page
BrickheadJohnny Jul 23, 2024
f17e5f5
upgrade package-lock
BrickheadJohnny Jul 23, 2024
3ed2048
fix: change banner color in dark mode
BrickheadJohnny Jul 23, 2024
e7b5e2c
cleanup: remove unused atom
BrickheadJohnny Jul 23, 2024
70907ee
cleanup(Carousel): remove `* as React` imports for consistency
BrickheadJohnny Jul 23, 2024
334d539
fix: adjust card sizes
BrickheadJohnny Jul 23, 2024
a754b70
feat: add purcase success effect
dominik-stumpf Jul 23, 2024
9bad238
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into pr…
BrickheadJohnny Jul 23, 2024
da0013a
chore: remove focus from button
dominik-stumpf Jul 23, 2024
7fb4166
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into pr…
dominik-stumpf Jul 23, 2024
fed6948
chore: remove hover effect on selected pass
dominik-stumpf Jul 23, 2024
f58c27e
fix: make text selectable
dominik-stumpf Jul 23, 2024
cbcaf64
Merge branch 'main' of github.com:guildxyz/guild.xyz into profiles-page
dominik-stumpf Jul 23, 2024
51f9e3c
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into pr…
dominik-stumpf Jul 23, 2024
b08037a
fix: remove shadon, update Layout
dominik-stumpf Jul 23, 2024
27aafce
chore: fix invalid tailwind class
dominik-stumpf Jul 23, 2024
bfbceb3
chore: add missed cn call to Layout
dominik-stumpf Jul 23, 2024
a0b5c65
chore: add basic logic to driver
dominik-stumpf Jul 23, 2024
e949913
chore: disable autoplay on dot button click
dominik-stumpf Jul 23, 2024
0005093
feat: add driver logic
dominik-stumpf Jul 23, 2024
6a14b6b
chore: rename data to chainData
dominik-stumpf Jul 23, 2024
6fa509e
fix: spread prev value too
dominik-stumpf Jul 23, 2024
e8e0ece
Merge branch 'main' into profiles-page
BrickheadJohnny Jul 24, 2024
f51c5b5
fix(ChoosePass): disable autoplay & start from the 2nd slide
BrickheadJohnny Jul 24, 2024
13bd101
fix: rename type
dominik-stumpf Jul 24, 2024
a19fbe3
feat: add emoji images
dominik-stumpf Jul 24, 2024
52576e3
revert: add layout and header back
dominik-stumpf Jul 24, 2024
378416c
chore: remove accidental line terminator
dominik-stumpf Jul 24, 2024
ac413d1
Merge branch 'main' of github.com:guildxyz/guild.xyz into profiles-page
dominik-stumpf Jul 24, 2024
4ffc831
wip: prepare components for animations
BrickheadJohnny Jul 24, 2024
ff00865
feat: add farcaster button
dominik-stumpf Jul 24, 2024
1aa6f41
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into pr…
dominik-stumpf Jul 24, 2024
30f4c24
chore: reposition driver buttons
dominik-stumpf Jul 24, 2024
a993155
feat: add destructive to button and required to label
dominik-stumpf Jul 24, 2024
24f634d
feat: migrate AllowanceButton
dominik-stumpf Jul 25, 2024
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
609 changes: 608 additions & 1 deletion package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,14 @@
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@react-three/drei": "^9.108.4",
"@react-three/fiber": "^8.16.8",
"@snyk/protect": "latest",
"@t3-oss/env-nextjs": "^0.10.1",
"@tanstack/react-query": "^5.26.3",
"@tanstack/react-table": "^8.13.2",
"@tanstack/react-virtual": "^3.5.0",
"@types/three": "^0.166.0",
"@vercel/kv": "^1.0.1",
"@vercel/postgres": "^0.7.2",
"@visx/curve": "^3.3.0",
Expand All @@ -76,6 +79,8 @@
"clsx": "^2.1.1",
"color": "^4.2.3",
"colorthief": "^2.3.2",
"embla-carousel-autoplay": "^8.1.6",
"embla-carousel-react": "^8.1.6",
"events": "^3.3.0",
"framer-motion": "^7.10.3",
"fuels": "^0.89.1",
Expand Down Expand Up @@ -108,6 +113,7 @@
"swr": "^2.2.4",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
"three": "^0.166.1",
"usehooks-ts": "^3.1.0",
"uuidv7": "^0.6.3",
"viem": "^2.17.0",
Expand Down
Binary file added public/apple_emojis/bust-in-silhouette.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/apple_emojis/compass.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/apple_emojis/people-with-bunny-ears.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/apple_emojis/sparkles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/apple_emojis/speech-balloon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/apple_emojis/star.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/apple_emojis/technologist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/apple_emojis/unlocked.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions src/app/(marketing)/create-profile/_components/Benefits.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Card } from "@/components/ui/Card"
import { cn } from "@/lib/utils"
import Image from "next/image"
import { BENEFITS } from "../constants"

export const Benefits = () => {
return (
<>
<h2 className="text-center font-bold text-muted-foreground text-xl leading-none tracking-tighter">
Benefits
</h2>
<p className="pb-4 text-center text-muted-foreground">
All passes provide the same benefits
</p>
<div className="grid grid-cols-1 gap-3 lg:grid-cols-2">
{BENEFITS.map(({ title, description, isAvailable, image }) => (
<Card
className={cn(
"flex items-center gap-4 border-2 border-transparent p-5",
{
"relative border-border border-dotted bg-transparent shadow-none":
!isAvailable,
}
)}
key={title}
>
{isAvailable || (
<div className="absolute top-2 right-1 w-24 translate-x-1/3 rotate-45 select-none bg-card py-1 text-center font-semibold text-xs">
Soon
</div>
)}
<div
className={cn(
"flex aspect-square min-w-12 items-center justify-center rounded-xl bg-card-secondary",
{ "bg-muted": !isAvailable }
)}
>
<Image src={image} alt="" width={28} height={28} />
</div>
<div className="space-y-1">
<h3 className="font-semibold">{title}</h3>
<p className="text-muted-foreground">{description}</p>
</div>
</Card>
))}
</div>
<p className="pt-10 text-center text-muted-foreground">
Prices are subject to change in the future
</p>
</>
)
}
118 changes: 118 additions & 0 deletions src/app/(marketing)/create-profile/_components/ChoosePass.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Button } from "@/components/ui/Button"
import {
Carousel,
CarouselApi,
CarouselContent,
CarouselDotButton,
CarouselItem,
useCarouselDotButton,
} from "@/components/ui/Carousel"
import { Separator } from "@/components/ui/Separator"
import { ToggleGroup, ToggleGroupItem } from "@radix-ui/react-toggle-group"
import { useEffect, useState } from "react"
import { SUBSCRIPTIONS } from "../constants"
import { OnboardingChain } from "../types"
import { Benefits } from "./Benefits"
import { GuildPassScene } from "./GuildPassScene"

export const ChoosePass: OnboardingChain = ({ dispatchChainAction }) => {
const [api, setApi] = useState<CarouselApi>()
const [subscriptionIndex, setSubscriptionIndex] = useState<number>()
const { selectedIndex, scrollSnaps, onCarouselDotButtonClick } =
useCarouselDotButton(api)
useEffect(() => {
if (subscriptionIndex === undefined) return
dispatchChainAction("next", {
chosenSubscription: SUBSCRIPTIONS[subscriptionIndex],
})
}, [subscriptionIndex])

return (
<div className="max-w-screen-lg">
<h1 className="mt-8 mb-4 h-10 text-center font-bold font-display text-2xl leading-none tracking-tight ">
Choose your pass
</h1>
<Carousel
className={"cursor-pointer active:cursor-grabbing lg:hidden"}
setApi={setApi}
opts={{
startIndex: 1,
}}
>
<CarouselContent>
{SUBSCRIPTIONS.map(({ title, description, pricing }, i) => (
<CarouselItem className="select-none" key={title}>
<article className="flex h-full flex-col items-center pb-6 text-center">
<div className="mb-2 h-48 w-full">
<GuildPassScene />{" "}
</div>
<div className="px-4">
<h2 className="font-extrabold text-lg">{title}</h2>
<strong className="font-extrabold text-lg text-orange-500">
{pricing}
</strong>
<p className="max-w-xs text-balance pt-2 text-muted-foreground text-sm">
{description}
</p>
<Button
colorScheme="primary"
className="mt-6 w-full"
onClick={() => setSubscriptionIndex(i)}
>
Purchase
</Button>
</div>
</article>
</CarouselItem>
))}
</CarouselContent>
</Carousel>
<div className="mb-4 space-x-3 self-center lg:hidden">
{scrollSnaps.map((_, i) => (
<CarouselDotButton
key={i}
onClick={() => onCarouselDotButtonClick(i)}
isActive={i === selectedIndex}
/>
))}
</div>

<ToggleGroup type="single" className="relative hidden items-end lg:flex">
{SUBSCRIPTIONS.map(({ title, description, pricing }, i) => (
<ToggleGroupItem
value={title}
onClick={() => setSubscriptionIndex(i)}
className={
"relative w-full select-none from-accent outline-none hover:bg-gradient-to-t focus-visible:bg-gradient-to-t focus-visible:ring-4 focus-visible:ring-ring"
}
key={title}
>
<article className="flex flex-col items-center pb-6 text-center">
<div className="mb-2 h-48">
<GuildPassScene />
</div>
<div className="px-8">
<h2 className="font-extrabold text-lg">{title}</h2>
<strong className="font-extrabold text-lg text-orange-500">
{pricing}
</strong>
<p className="max-w-xs text-balance pt-2 text-muted-foreground text-sm">
{description}
</p>
</div>
{i < SUBSCRIPTIONS.length - 1 && (
<Separator
orientation="vertical"
className="absolute right-0 block bg-[none] bg-gradient-to-t from-border to-60%"
/>
)}
</article>
</ToggleGroupItem>
))}
</ToggleGroup>
<div className="space-y-4 border-border border-t bg-background p-8">
<Benefits />
</div>
</div>
)
}
67 changes: 67 additions & 0 deletions src/app/(marketing)/create-profile/_components/ClaimPass.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Button } from "@/components/ui/Button"
import {
FormControl,
FormDescription,
FormErrorMessage,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/Form"
import { Input } from "@/components/ui/Input"
import { zodResolver } from "@hookform/resolvers/zod"
import { ArrowRight } from "@phosphor-icons/react/dist/ssr"
import { FormProvider, useForm } from "react-hook-form"
import { z } from "zod"
import { OnboardingChain } from "../types"
import { GuildPassScene } from "./GuildPassScene"

const formSchema = z.object({
inviteHandle: z.string(),
})

export const ClaimPass: OnboardingChain = ({ dispatchChainAction }) => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
inviteHandle: "",
},
})
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
dispatchChainAction("next")
}

return (
<div className="max-w-md p-8">
<div className="mb-12 h-48 w-full">
<GuildPassScene />
</div>
<h1 className="mb-14 text-pretty text-center font-extrabold text-2xl leading-none tracking-tighter">
Claim your Guild Pass and begin an epic adventure!
</h1>

<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="inviteHandle"
render={({ field }) => (
<FormItem>
<FormLabel>Invite handle</FormLabel>
<FormControl>
<Input placeholder="" {...field} />
</FormControl>
<FormDescription>Guild Pass is invite only</FormDescription>
<FormErrorMessage />
</FormItem>
)}
/>
<Button type="submit" colorScheme="success" className="w-full">
Continue
<ArrowRight weight="bold" />
</Button>
</form>
</FormProvider>
</div>
)
}
33 changes: 33 additions & 0 deletions src/app/(marketing)/create-profile/_components/GuildPassScene.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use client"

import { Float } from "@react-three/drei"
import { Canvas, ThreeElements } from "@react-three/fiber"
import * as THREE from "three"

function GuildPass(props: ThreeElements["mesh"]) {
return (
<mesh {...props} scale={4} rotation={new THREE.Euler(0.0, 0.1, 0.0)}>
<boxGeometry args={[1.4, 0.6, 0.1]} />
<meshStandardMaterial color="orange" wireframe />
</mesh>
)
}

export const GuildPassScene = () => {
return (
<Canvas>
<ambientLight intensity={Math.PI / 2} />
<spotLight
position={[10, 10, 10]}
angle={0.15}
penumbra={1}
decay={0}
intensity={Math.PI}
/>
<pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} />
<Float floatIntensity={6} speed={2.4}>
<GuildPass position={[0, 0, 0]} />
</Float>
</Canvas>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"use client"

import { Button } from "@/components/ui/Button"
import { cardClassName } from "@/components/ui/Card"
import { cn } from "@/lib/utils"
import { useState } from "react"
import { SUBSCRIPTIONS } from "../constants"
import { ChainData, DispatchChainAction, OnboardingChain } from "../types"
import { ChoosePass } from "./ChoosePass"
import { ClaimPass } from "./ClaimPass"
import { PurchasePass } from "./PurchasePass"
import { StartProfile } from "./StartProfile"

const chains: OnboardingChain[] = [
ClaimPass,
ChoosePass,
PurchasePass,
StartProfile,
] as const

export const OnboardingDriver = () => {
const [chainIndex, setChainIndex] = useState(1)
// TODO: remove default chosen subscription, as it is only there for debug
// purposes
const [chainData, setChainData] = useState<Partial<ChainData>>({
chosenSubscription: SUBSCRIPTIONS[0],
})
const OnboardingCard = chains[chainIndex]

const dispatchChainAction: DispatchChainAction = (action, data) => {
setChainData((prev) => ({ ...prev, ...data }))
if (action === "next" && chains.length > chainIndex + 1) {
setChainIndex((prev) => prev + 1)
return
}
if (action === "previous" && 0 < chainIndex) {
setChainIndex((prev) => prev - 1)
}
}

return (
<>
<div className="fixed bottom-4 left-4 z-10 space-x-2">
<Button onClick={() => dispatchChainAction("previous")}>previous</Button>
<Button onClick={() => dispatchChainAction("next")}>next</Button>
</div>

<div
className={cn(
cardClassName,
"mx-auto max-w-max bg-gradient-to-b from-card to-card-secondary shadow-2xl"
)}
// layout
// style={{
// borderRadius: "16px",
// }}
>
{/* <AnimatePresence mode="popLayout" initial={false}>
<motion.div
key={chainIndex}
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
}}
exit={{
opacity: 0,
}}
transition={{
duration: 0.24,
}}
className="overflow-hidden"
> */}
<OnboardingCard
dispatchChainAction={dispatchChainAction}
chainData={chainData}
/>
{/* </motion.div>
</AnimatePresence> */}
</div>
</>
)
}
Loading
Loading