Skip to content

Commit

Permalink
feat: connect sign in and signup api
Browse files Browse the repository at this point in the history
  • Loading branch information
DanSnow committed Feb 5, 2024
1 parent 206e2a5 commit 6a7095e
Show file tree
Hide file tree
Showing 19 changed files with 348 additions and 49 deletions.
2 changes: 2 additions & 0 deletions auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ declare global {
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
const controlledRef: typeof import('@vueuse/core')['controlledRef']
const createApp: typeof import('vue')['createApp']
const createClientOptions: typeof import('./src/utils/urql')['createClientOptions']
const createEventHook: typeof import('@vueuse/core')['createEventHook']
const createGenericProjection: typeof import('@vueuse/math')['createGenericProjection']
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
Expand Down Expand Up @@ -264,6 +265,7 @@ declare global {
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
const useStore: typeof import('@nanostores/vue')['useStore']
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
const useSubscribe: typeof import('./src/composables/auth')['useSubscribe']
const useSum: typeof import('@vueuse/math')['useSum']
const useSupported: typeof import('@vueuse/core')['useSupported']
const useSwipe: typeof import('@vueuse/core')['useSwipe']
Expand Down
9 changes: 9 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ declare module 'vue' {
CardHeader: typeof import('./src/components/ui/card/CardHeader.vue')['default']
CardTitle: typeof import('./src/components/ui/card/CardTitle.vue')['default']
DevPanel: typeof import('./src/components/DevPanel.vue')['default']
Dialog: typeof import('./src/components/ui/dialog/Dialog.vue')['default']
DialogClose: typeof import('./src/components/ui/dialog/DialogClose.vue')['default']
DialogContent: typeof import('./src/components/ui/dialog/DialogContent.vue')['default']
DialogDescription: typeof import('./src/components/ui/dialog/DialogDescription.vue')['default']
DialogFooter: typeof import('./src/components/ui/dialog/DialogFooter.vue')['default']
DialogHeader: typeof import('./src/components/ui/dialog/DialogHeader.vue')['default']
DialogTitle: typeof import('./src/components/ui/dialog/DialogTitle.vue')['default']
DialogTrigger: typeof import('./src/components/ui/dialog/DialogTrigger.vue')['default']
EmailForm: typeof import('./src/components/EmailForm.vue')['default']
FormControl: typeof import('./src/components/ui/form/FormControl.vue')['default']
FormDescription: typeof import('./src/components/ui/form/FormDescription.vue')['default']
Expand All @@ -39,6 +47,7 @@ declare module 'vue' {
Input: typeof import('./src/components/ui/input/Input.vue')['default']
Label: typeof import('./src/components/ui/label/Label.vue')['default']
LeakyPaywall: typeof import('./src/components/LeakyPaywall.vue')['default']
LoginDialog: typeof import('./src/components/LoginDialog.vue')['default']
Popover: typeof import('./src/components/ui/popover/Popover.vue')['default']
PopoverContent: typeof import('./src/components/ui/popover/PopoverContent.vue')['default']
PopoverTrigger: typeof import('./src/components/ui/popover/PopoverTrigger.vue')['default']
Expand Down
2 changes: 2 additions & 0 deletions moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,7 @@ tasks:
- yarn.lock
dev:
command: vite
args:
- --open
local: true
platform: node
7 changes: 2 additions & 5 deletions src/PaywallRoot.ce.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<script setup lang="ts">
import { cacheExchange, fetchExchange, provideClient } from '@urql/vue'
import { provideClient } from '@urql/vue'
const target = ref<ComponentPublicInstance | null>(null)
provideRoot(target)
provideClient({
url: `https://api.storipress.dev/${window.SP_PAYWALL.clientId}/graphql`,
exchanges: [cacheExchange, fetchExchange],
})
provideClient(createClientOptions(window.SP_PAYWALL.clientId))
</script>
<template>
<div>
Expand Down
17 changes: 12 additions & 5 deletions src/components/EmailForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as z from 'zod'
import { useModel } from 'vue'
const props = defineProps<{
mode: 'subscribe' | 'login'
email: string
buttonText: string
}>()
Expand All @@ -32,11 +33,15 @@ const form = useForm({
})
const emailInput = useModel(props, 'email')
const { subscribe } = useSubscribe(toRef(props, 'mode'))
// TODO: handle submit user email
const onSubmit = form.handleSubmit((values) => {
// eslint-disable-next-line no-console
console.log('Form submitted!', values)
const showLoginDialog = ref(false)
const onSubmit = form.handleSubmit(async (values) => {
const res = await subscribe(values)
if (res.ok && !res.token) {
showLoginDialog.value = true
}
})
const [formItem, setAnimate] = useAutoAnimate({ duration: 200 })
Expand Down Expand Up @@ -65,12 +70,14 @@ onMounted(async () => {
v-bind="componentField"
/>
</FormControl>
<FormMessage v-if="(console.log(meta), meta.touched)" />
<FormMessage v-if="meta.touched" />
</FormItem>
</FormField>

<Button type="submit" tabindex="-1" class="w-full bg-sp_primary text-white">
{{ buttonText }}
</Button>

<LoginDialog v-model:open="showLoginDialog" />
</form>
</template>
6 changes: 3 additions & 3 deletions src/components/LeakyPaywall.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ initConfig()
const config = useStore($config)
const mode = ref<'subscribe' | 'signup'>('subscribe')
const mode = ref<'subscribe' | 'login'>('subscribe')
const primaryButton = computed(() => (mode.value === 'subscribe' ? 'Subscribe' : 'Sign in'))
const secondaryButton = computed(() => (mode.value === 'subscribe' ? 'Sign in' : 'Subscribe'))
Expand All @@ -23,7 +23,7 @@ const emailInput = ref('')
function switchMode() {
// After this step, the form will be reset
mode.value = mode.value === 'subscribe' ? 'signup' : 'subscribe'
mode.value = mode.value === 'subscribe' ? 'login' : 'subscribe'
}
// Unlock scroll if user scroll up
Expand Down Expand Up @@ -98,7 +98,7 @@ whenever(
</p>

<!-- email form -->
<EmailForm :key="mode" v-model:email="emailInput" :button-text="primaryButton" />
<EmailForm :key="mode" v-model:email="emailInput" :mode="mode" :button-text="primaryButton" />

<Separator class="my-2" />

Expand Down
23 changes: 23 additions & 0 deletions src/components/LoginDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import { useForwardPropsEmits } from 'radix-vue'
const props = defineProps<{ open: boolean }>()
const emit = defineEmits<{ 'update:open': [boolean] }>()
const args = useForwardPropsEmits(props, emit)
</script>

<template>
<Dialog v-bind="args">
<DialogContent>
<DialogHeader>
<DialogTitle>We’ve sent you a login link!</DialogTitle>
<DialogDescription>If the email doesn't arrive in 3 minutes, check your spam folder.</DialogDescription>
</DialogHeader>

<DialogFooter>
<Button @click="$emit('update:open', false)">OK</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template>
14 changes: 14 additions & 0 deletions src/components/ui/dialog/Dialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script setup lang="ts">
import { DialogRoot, type DialogRootEmits, type DialogRootProps, useForwardPropsEmits } from 'radix-vue'
const props = defineProps<DialogRootProps>()
const emits = defineEmits<DialogRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>

<template>
<DialogRoot v-bind="forwarded">
<slot />
</DialogRoot>
</template>
11 changes: 11 additions & 0 deletions src/components/ui/dialog/DialogClose.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { DialogClose, type DialogCloseProps } from 'radix-vue'
const props = defineProps<DialogCloseProps>()
</script>

<template>
<DialogClose v-bind="props">
<slot />
</DialogClose>
</template>
50 changes: 50 additions & 0 deletions src/components/ui/dialog/DialogContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import {
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'radix-vue'
import { X } from 'lucide-vue-next'
import { cn } from '~/lib/utils'
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DialogContentEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
/>
<DialogContent
v-bind="forwarded"
:class="
cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
props.class,
)"
>
<slot />

<DialogClose
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X class="w-4 h-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
</template>
24 changes: 24 additions & 0 deletions src/components/ui/dialog/DialogDescription.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'radix-vue'
import { cn } from '~/lib/utils'
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>

<template>
<DialogDescription
v-bind="forwardedProps"
:class="cn('text-sm text-muted-foreground', props.class)"
>
<slot />
</DialogDescription>
</template>
19 changes: 19 additions & 0 deletions src/components/ui/dialog/DialogFooter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '~/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
</script>

<template>
<div
:class="
cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
props.class,
)
"
>
<slot />
</div>
</template>
16 changes: 16 additions & 0 deletions src/components/ui/dialog/DialogHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '~/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>

<template>
<div
:class="cn('flex flex-col gap-y-1.5 text-center sm:text-left', props.class)"
>
<slot />
</div>
</template>
29 changes: 29 additions & 0 deletions src/components/ui/dialog/DialogTitle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { DialogTitle, type DialogTitleProps, useForwardProps } from 'radix-vue'
import { cn } from '~/lib/utils'
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>

<template>
<DialogTitle
v-bind="forwardedProps"
:class="
cn(
'text-lg font-semibold leading-none tracking-tight',
props.class,
)
"
>
<slot />
</DialogTitle>
</template>
11 changes: 11 additions & 0 deletions src/components/ui/dialog/DialogTrigger.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { DialogTrigger, type DialogTriggerProps } from 'radix-vue'
const props = defineProps<DialogTriggerProps>()
</script>

<template>
<DialogTrigger v-bind="props">
<slot />
</DialogTrigger>
</template>
8 changes: 8 additions & 0 deletions src/components/ui/dialog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { default as Dialog } from './Dialog.vue'
export { default as DialogClose } from './DialogClose.vue'
export { default as DialogTrigger } from './DialogTrigger.vue'
export { default as DialogHeader } from './DialogHeader.vue'
export { default as DialogTitle } from './DialogTitle.vue'
export { default as DialogDescription } from './DialogDescription.vue'
export { default as DialogContent } from './DialogContent.vue'
export { default as DialogFooter } from './DialogFooter.vue'
Loading

0 comments on commit 6a7095e

Please sign in to comment.