Implement SignIn/SignOut

This commit is contained in:
Jorge Vargas 2024-11-15 12:58:43 -06:00
parent bce35d73ca
commit adeb3fd3bf
16 changed files with 987 additions and 77 deletions

View file

@ -1,12 +0,0 @@
---
const { class: className } = Astro.props
---
<button
class:list={[
'bg-blue-600 hover:bg-blue-700 py-2 px-3.5 rounded-lg',
className
]}
>
<slot />
</button>

26
src/components/Button.tsx Normal file
View file

@ -0,0 +1,26 @@
import type { PropsWithChildren } from 'react'
import clsx from 'clsx'
import { BarsRotateFade } from 'react-svg-spinners'
export default function Button(props: PropsWithChildren<{ className?: string; loading?: boolean }>) {
const { children, className, loading = false, ...restProps } = props
return (
<button
className={clsx(
loading ? 'bg-blue-400 cursor-progress' : 'bg-blue-600 hover:bg-blue-700',
'py-2 px-3.5 rounded-lg',
className
)}
{...restProps}
>
<div className='relative flex'>
<span className={clsx({ invisible: loading })}>{children}</span>
{loading ? (
<div className='absolute top-0 left-0 w-full flex justify-center'>
<BarsRotateFade color='white' />
</div>
) : null}
</div>
</button>
)
}

View file

@ -1,6 +1,6 @@
---
import { gql } from '@/graphql/__generated__/client/index.js'
import { getApolloClient } from '@/graphql/apolloClient.js'
import { getApolloClient } from '@/graphql/apolloClientSSR.js'
import { Image, Picture } from 'astro:assets'
import { getSession } from 'auth-astro/server'
import * as m from '../paraglide/messages.js'
@ -8,11 +8,11 @@ import * as m from '../paraglide/messages.js'
import logo from 'img/logos/winter.png'
// import logoEs from 'img/logos/default_es.png'
import Button from './Button.astro'
import Dropdown from './header/Dropdown.astro'
import DropdownItem from './header/DropdownItem.astro'
import Toggler from './header/Toggler.astro'
import NavButton from './header/NavButton.astro'
import LoginNav from './header/LoginNav.astro'
const headerQuery = gql(`
query HeaderInfo {
@ -48,16 +48,7 @@ const session = await getSession(Astro.request)
<Image src={logo} class='h-full py-0.5 w-auto' alt='logo' height={150} width={265} />
</a>
<div class='absolute top-0 right-0 space-x-2 mr-10'>
{
session === null ? (
<Button class='rounded-t-none'>{m.login()}</Button>
) : (
<Button class='rounded-t-none'>{m.logout()}</Button>
)
}
<Button class='rounded-t-none'>{m.register()}</Button>
</div>
<LoginNav />
</div>
</div>
<nav class='w-full md:h-[55px] bg-dark'>

View file

@ -0,0 +1,15 @@
---
import { getSession } from 'auth-astro/server'
import { SignIn, SignOut } from 'auth-astro/components'
import RegisterBtn from './RegisterButton'
import * as m from 'paraglide/messages.js'
const session = await getSession(Astro.request)
const btnClass = 'bg-blue-600 hover:bg-blue-700 py-2 px-3.5 rounded-lg rounded-t-none'
---
<div class='absolute top-0 right-0 space-x-2 mr-10'>
{session === null ? <SignIn class={btnClass}>{m.login()}</SignIn> : <SignOut class={btnClass}>{m.logout()}</SignOut>}
{!session ? <RegisterBtn client:only='react' /> : null}
</div>

View file

@ -1,14 +1,15 @@
---
import Button from '../Button.astro'
import Button from '../Button'
import clsx from 'clsx'
const { class: className } = Astro.props
---
<Button
class:list={[
className={clsx(
'w-full md:w-fit md:h-full bg-dark hover:bg-dark-hover py-3.5 md:py-1 px-2 rounded-none text-left md:text-center',
className
]}
)}
>
<slot />
</Button>

View file

@ -1,23 +1,15 @@
import { ApolloClient, InMemoryCache } from '@apollo/client/core'
import { SchemaLink } from '@apollo/client/link/schema'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { getSession } from 'auth-astro/server'
import type { Session } from '@auth/core/types'
import prismaClient, { type users } from 'prisma/client'
import createUploadLink from 'apollo-upload-client/createUploadLink.mjs'
import { typeDefs } from './__generated__/typeDefs.generated'
import resolvers from '@/graphql/resolvers'
const httpLink = createUploadLink({
uri: `${window.origin}/api/graphql`,
headers: { 'Apollo-Require-Preflight': true },
credentials: 'include'
})
const schema = makeExecutableSchema({ typeDefs, resolvers })
export type ResolverContext = { request?: Request; session?: Session; user?: users }
const apolloClient = new ApolloClient({
link: httpLink,
cache: new InMemoryCache()
})
export async function getApolloClient(request?: Request) {
const session = async () => (request ? getSession(request) : null)
const user = async () => (session ? prismaClient.users.findUnique({ where: { username: session.id } }) : null)
return new ApolloClient({
ssrMode: true,
link: new SchemaLink({ schema, context: { request, session, user } }),
cache: new InMemoryCache()
})
}
export default apolloClient

View file

@ -0,0 +1,24 @@
import { ApolloClient, InMemoryCache } from '@apollo/client/core'
import { SchemaLink } from '@apollo/client/link/schema'
import { getSession } from 'auth-astro/server'
import type { Session } from '@auth/core/types'
import prismaClient, { type users } from 'prisma/client'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { typeDefs } from '@/graphql/__generated__/typeDefs.generated'
import resolvers from '@/graphql/resolvers'
export type ResolverContext = { request?: Request; session?: Session; user?: users }
const schema = makeExecutableSchema({ typeDefs, resolvers })
export async function getApolloClient(request?: Request) {
const session = async () => (request ? getSession(request) : null)
const user = async () => (session ? prismaClient.users.findUnique({ where: { username: session.id } }) : null)
return new ApolloClient({
ssrMode: true,
link: new SchemaLink({ schema, context: { request, session, user } }),
cache: new InMemoryCache()
})
}

View file

@ -38,10 +38,7 @@ type Query {
}
type Mutation {
login(username: String!, password: String!): Int!
logout: Int!
registerUser(email: String!, username: String!, pfp: Upload): Boolean!
registerUser(email: String!, username: String!, pfp: File): Boolean!
updateUserRoles(username: String!, roles: [String]!): Boolean!
deleteUser(username: String!): Int

View file

@ -1,7 +1,7 @@
import rss, { type RSSFeedItem } from '@astrojs/rss'
import type { APIContext } from 'astro'
import { getApolloClient } from '@/graphql/apolloClient.js'
import { getApolloClient } from '@/graphql/apolloClientSSR'
import { gql } from '@/graphql/__generated__/client'
const addedQuery = gql(`

View file

@ -0,0 +1,13 @@
import { GraphQLError } from 'graphql'
import { ApolloServerErrorCode } from '@apollo/server/errors'
export const AuthenticationError = (message: string = '') =>
new GraphQLError(message, { extensions: { code: 'UNAUTHENTICATED' } })
export const ForbiddenError = (message: string = '') =>
new GraphQLError(message, { extensions: { code: 'FORBIDDEN' } })
export const UserInputError = (message: string = '') =>
new GraphQLError(message, {
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT }
})