import {gql, useQuery} from '@apollo/client'
🚗 import { Redirect } from 'react-router'
const IS_LOGGED_IN = gql`
{
me {
id
}
}
`
interface Props {
children?: React.ReactNode
}
const IsAuthenticated = ({children} : Props) => {
const{loading, error, data} = useQuery(IS_LOGGED_IN)
if(loading) return <p>Loading...</p>
if(error) return <p>{error.message}</p>
if (!data.me) {
return <Redirect to={{pathname : '/landing'}} />
}
return <>{children}</>
}
export default IsAuthenticated;
🚗 import { Redirect } from 'react-router'
1. Rendering a will navigate to a new location.
2. The new location will override
the current location in the history stack,
like server-side redirects (HTTP 3xx) do
.
import { ApolloClient, InMemoryCache, ApolloProvider, HttpLink } from '@apollo/client';
import Users from './components/Users';
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import Landing from './components/Landing';
import {setContext} from 'apollo-link-context';
import Signup from './pages/Signup';
import Login from './pages/Login';
import IsAuthenticated from './components/IsAuthenticated';
const httpLink = new HttpLink({uri:'http://localhost:4000'})
const authlink = setContext( async( req, { headers } ) => {
const token = localStorage.getItem('token')
return {
...headers,
headers:{
Authorization: token ? `Bearer ${token}` : null
}
}
})
const link = authlink.concat(httpLink as any)
const client = new ApolloClient(
{
link: (link as any),
cache: new InMemoryCache()}
)
function App() {
return (
<ApolloProvider client={client}>
<Router>
<Switch>
<Route path="/landing">
<Landing />
</Route>
<Route path="/signup">
<Signup />
</Route>
<Route path="/login">
<Login />
</Route>
<IsAuthenticated>
🚗 <Route path="/users">
<Users />
</Route>
</IsAuthenticated>
</Switch>
</Router>
</ApolloProvider>
);
}
export default App;
🚗 <Route path="/users"> <Users /> </Route>
1. IsAuthenticated.tsx's Props.children
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// DataBadse로 집어넣을 정보들에 대한 Schema
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
model User {
id Int @id @default(autoincrement())
email String @unique
password String @default("")
name String?
Profile Profile?
tweets Tweet[]
Post Post[]
}
model Profile {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
bio String?
location String?
website String?
avatar String?
userId Int? @unique
User User? @relation(fields: [userId], references: [id])
}
model Tweet {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
content String
author User? @relation(fields: [authorID], references: [id])
authorID Int?
}
// npx prisma migrate dev --preview-feature
// Manually writing the data model and mapping it to the database with Prisma Migrate
import { objectType } from 'nexus'
export const Profile = objectType({
name: 'Profile',
definition(t) {
t.model.id()
t.model.bio()
t.model.location()
t.model.website()
t.model.avatar()
},
})
import { objectType } from 'nexus'
export const Tweet = objectType({
name: 'Tweet',
definition(t) {
t.model.id()
t.model.content()
t.model.author()
},
})
import { compare, hash } from 'bcryptjs'
import { sign } from 'jsonwebtoken'
import { intArg, mutationType, nonNull, stringArg } from 'nexus'
import { APP_SECRET, getUserId } from '../utils'
export const Mutation = mutationType({
definition(t) {
t.field('signup', {
type: 'AuthPayload',
args: {
name: stringArg(),
email: nonNull(stringArg()),
password: nonNull(stringArg()),
},
resolve: async (_parent, { name, email, password }, ctx) => {
const hashedPassword = await hash(password, 10)
const user = await ctx.prisma.user.create({
data: {
name,
email,
password: hashedPassword,
},
})
return {
token: sign({ userId: user.id }, APP_SECRET),
user,
}
},
})
t.field('login', {
type: 'AuthPayload',
args: {
email: nonNull(stringArg()),
password: nonNull(stringArg()),
},
resolve: async (_parent, { email, password }, ctx) => {
const user = await ctx.prisma.user.findUnique({
where: {
email,
},
})
if (!user) {
throw new Error(`No user found for email: ${email}`)
}
const passwordValid = await compare(password, user.password)
if (!passwordValid) {
throw new Error('Invalid password')
}
return {
token: sign({ userId: user.id }, APP_SECRET),
user,
}
},
})
t.field("createProfile", {
type: "Profile",
args: {
bio: stringArg(),
location: stringArg(),
website: stringArg(),
avatar: stringArg()
},
resolve: (parent, args, ctx) => {
const userId = getUserId(ctx)
if (!userId) throw new Error("Could not authenticate user.")
return ctx.prisma.profile.create({
data: {
...args,
User: { connect: { id: Number(userId) } }
}
})
}
})
t.field("updateProfile", {
type: "Profile",
args: {
id: intArg(),
bio: stringArg(),
location: stringArg(),
website: stringArg(),
avatar: stringArg()
},
resolve: (parent, {id, ...args}, ctx) => {
const userId = getUserId(ctx)
if (!userId) throw new Error("Could not authenticate user.")
return ctx.prisma.profile.update({
data: {
...args,
},
where: {
id: Number(id)
}
})
}
})
// t.field('createDraft', {
// type: 'Post',
// args: {
// title: nonNull(stringArg()),
// content: stringArg(),
// },
// resolve: (parent, { title, content }, ctx) => {
// const userId = getUserId(ctx)
// if (!userId) throw new Error('Could not authenticate user.')
// return ctx.prisma.post.create({
// data: {
// title,
// content,
// published: false,
// author: { connect: { id: Number(userId) } },
// },
// })
// },
// })
// t.nullable.field('deletePost', {
// type: 'Post',
// args: { id: nonNull(intArg()) },
// resolve: (parent, { id }, ctx) => {
// return ctx.prisma.post.delete({
// where: {
// id,
// },
// })
// },
// })
// t.nullable.field('publish', {
// type: 'Post',
// args: {
// id: nonNull(intArg()),
// },
// resolve: (parent, { id }, ctx) => {
// return ctx.prisma.post.update({
// where: { id },
// data: { published: true },
// })
// },
// })
},
})
import { intArg, nullable, queryType, stringArg } from 'nexus'
import { getUserId } from '../utils'
export const Query = queryType({
definition(t) {
t.nullable.field('me', {
type: 'User',
resolve: (parent, args, ctx) => {
const userId = getUserId(ctx)
return ctx.prisma.user.findUnique({
where: {
id: Number(userId),
},
})
},
})
t.list.field('users', {
type: 'User',
resolve: (parent, args, ctx) => {
return ctx.prisma.user.findMany()
},
})
// t.list.field('filterPosts', {
// type: 'Post',
// args: {
// searchString: nullable(stringArg()),
// },
// resolve: (parent, { searchString }, ctx) => {
// return ctx.prisma.post.findMany({
// where: {
// OR: [
// {
// title: {
// contains: searchString || undefined,
// },
// },
// {
// content: {
// contains: searchString ?? undefined,
// },
// },
// ],
// },
// })
// },
// })
// t.nullable.field('post', {
// type: 'Post',
// args: { id: intArg() },
// resolve: (parent, { id }, ctx) => {
// return ctx.prisma.post.findUnique({
// where: {
// id: Number(id),
// },
// })
// },
// })
},
})