diff --git a/client/src/components/App.js b/client/src/components/App.js
index 3b5fcd4..23c8857 100644
--- a/client/src/components/App.js
+++ b/client/src/components/App.js
@@ -4,6 +4,7 @@ import Header from './Header';
import { Switch, Route } from 'react-router-dom';
// import ProductList from './ProductList';
import AppointmentList from './AppointmentList';
+import Login from './Login';
const App = () => {
return (
@@ -14,6 +15,7 @@ const App = () => {
{/* */}
+
diff --git a/client/src/components/CreateAppointment.js b/client/src/components/CreateAppointment.js
index dd84c7d..7c2e7c8 100644
--- a/client/src/components/CreateAppointment.js
+++ b/client/src/components/CreateAppointment.js
@@ -10,8 +10,10 @@ const CREATE_APPOINTMENT_MUTATION = gql`
mutation CreateAppointmentMutation(
$title: String!
$description: String!
+ $timeStart: String!
+ $timeEnd: String!
) {
- createAppointment(title: $title, description: $description) {
+ createAppointment(title: $title, description: $description, timeStart: $timeStart, timeEnd: $timeEnd) {
id
title
description
diff --git a/client/src/components/Header.js b/client/src/components/Header.js
index ae4fbbc..aa16ecb 100644
--- a/client/src/components/Header.js
+++ b/client/src/components/Header.js
@@ -1,23 +1,30 @@
import React from 'react';
-// import { useHistory } from 'react-router';
+import { useHistory } from 'react-router';
import { Link, withRouter } from 'react-router-dom';
+import { AUTH_TOKEN } from '../constants';
const Header = () => {
- // const history = useHistory();
+ const history = useHistory();
+ const authToken = localStorage.getItem(AUTH_TOKEN);
return (
Store!
-
- Top list
-
+
Top list
---
-
- Create new
-
+
Create new
+
+
+ {authToken ? (
+
{
+ localStorage.removeItem(AUTH_TOKEN);
+ history.push(`/`);
+ }}
+ >Logout
+ ) : (
+
Login
+ )}
);
diff --git a/client/src/components/Login.js b/client/src/components/Login.js
index 47ec480..db1e928 100644
--- a/client/src/components/Login.js
+++ b/client/src/components/Login.js
@@ -12,7 +12,7 @@ const SIGNUP_MUTATION = gql`
signup(
email: $email
password: $password
- name: $name
+ username: $name
) {
token
}
diff --git a/client/src/index.js b/client/src/index.js
index da1ddc1..4061cad 100644
--- a/client/src/index.js
+++ b/client/src/index.js
@@ -1,8 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './styles/index.css';
+import { AUTH_TOKEN } from './constants';
import App from './components/App';
import { BrowserRouter } from 'react-router-dom';
+import { setContext } from '@apollo/client/link/context';
// import * as serviceWorker from './serviceWorker';
import {
@@ -16,8 +18,19 @@ const httpLink = createHttpLink({
uri: 'http://localhost:4000/graphql'
});
+const authLink = setContext((_, { headers }) => {
+ const token = localStorage.getItem(AUTH_TOKEN);
+ return {
+ headers: {
+ ...headers,
+ authorization: token ? `Bearer ${token}` : ''
+ }
+ };
+});
+
const client = new ApolloClient({
- link: httpLink,
+ link: authLink.concat(httpLink),
+ // link: httpLink,
cache: new InMemoryCache()
});
diff --git a/server/src/models/user.js b/server/src/models/user.js
new file mode 100644
index 0000000..b35e617
--- /dev/null
+++ b/server/src/models/user.js
@@ -0,0 +1,21 @@
+import mongoose from 'mongoose';
+const Schema = mongoose.Schema;
+const UserSchema = new Schema({
+ username: {
+ type: String,
+ required: true
+ },
+ email: {
+ type: String,
+ required: true
+ },
+ password: {
+ type: String,
+ required: true
+ },
+ deleted: {
+ type: Boolean,
+ required: false
+ }
+});
+export default mongoose.model('user', UserSchema);
\ No newline at end of file
diff --git a/server/src/resolvers.js b/server/src/resolvers.js
index c8a4924..381ef62 100644
--- a/server/src/resolvers.js
+++ b/server/src/resolvers.js
@@ -1,7 +1,11 @@
// import Appointment from '../../client/src/components/Appointment.js';
import Product from './models/product.js';
import Appointment from './models/appointment.js';
+import User from './models/user.js'
// import { createAppointment } from './resolvers/Mutation.js';
+import bcrypt from 'bcryptjs';
+import jwt from 'jsonwebtoken';
+import dotenv from 'dotenv';
export const resolvers = {
Query: {
@@ -11,8 +15,58 @@ export const resolvers = {
async allProducts() {
return await Product.find();
},
+ async allUsers() {
+ return await User.find();
+ },
},
Mutation: {
+ async signup(root, {
+ input
+ }) {
+ console.log(input.password);
+ input.password = await bcrypt.hash(input.password, 10);
+
+ const user = await User.create(input);
+
+ const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET);
+
+ return {
+ token,
+ user
+ };
+ },
+
+ async login(root, {
+ email, password
+ }) {
+ const user = await User.findOne({
+ email: email
+ });
+
+ if (!user) {
+ throw new Error('No such user found');
+ }
+
+ const pwd = await bcrypt.hash(password, 10);
+ console.log(pwd);
+ console.log(user.password);
+
+ const valid = await bcrypt.compare(
+ password,
+ user.password
+ );
+ if (!valid) {
+ throw new Error('Invalid password');
+ }
+
+ const token = jwt.sign({ userId: user.id }, APP_SECRET);
+
+ return {
+ token,
+ user
+ };
+ },
+
async createAppointment(root, {
input
}) {
diff --git a/server/src/schema.graphql b/server/src/schema.graphql
index 8049368..8b309ee 100644
--- a/server/src/schema.graphql
+++ b/server/src/schema.graphql
@@ -8,6 +8,7 @@ type Query {
): Feed!
allProducts: [Product]
allAppointments: [Appointment]
+ allUsers: [User]
users: [User!]!
}
@@ -39,9 +40,7 @@ type Mutation {
_id: ID!
) : Product
signup(
- email: String!
- password: String!
- name: String!
+ input: UserInput
): AuthPayload
login(
email: String!,
@@ -57,19 +56,26 @@ type Subscription {
newFollow: Follow
}
+#User Schemas
+type User {
+ _id: ID!
+ username: String!
+ email: String!
+ password: String!
+ # appointments: [Appointment!]!
+}
+input UserInput{
+ username: String!
+ email: String!
+ password: String!
+ # appointments: [Appointment!]!
+}
type AuthPayload {
token: String
user: User
}
-type User {
- _id: ID!
- name: String!
- email: String!
- appointments: [Appointment!]!
-}
-
-# Appointment model
+# Appointment schemas
type Appointment {
_id: ID!
title: String!
@@ -91,8 +97,13 @@ input AppointmentInput {
timeStart: Time!
timeEnd: Time!
}
+input AppointmentOrderByInput {
+ description: Sort
+ url: Sort
+ createdAt: Sort
+}
-# Product model
+# Product schemas
type Product {
_id: ID!
title: String!
@@ -103,23 +114,17 @@ input ProductInput {
qty: Int
}
+# Follow schemas
type Follow {
_id: ID!
appointment: Appointment!
user: User!
}
-
-input AppointmentOrderByInput {
- description: Sort
- url: Sort
- createdAt: Sort
-}
-
+# General-purpose schemas
enum Sort {
asc
desc
}
-
scalar DateTime
scalar Time