This commit is contained in:
Riccardo
2021-01-03 20:53:38 +01:00
parent e72890fe28
commit 61acbf02d8
12 changed files with 282 additions and 241 deletions

View File

@@ -1,13 +1,9 @@
// import logo from './../logo.svg'; import React from 'react';
// import './../styles/App.css'; // import CreateAppointment from './CreateAppointment';
import React, { Component } from 'react';
import AppointmentList from './AppointmentList';
import CreateAppointment from './CreateAppointment'
import Header from './Header'; import Header from './Header';
import Login from './Login' // import AppointmentList from './AppointmentList';
import Search from './Search'; import ProductList from './ProductList';
import { Redirect, Route, Switch } from 'react-router-dom'; import { Switch, Route } from 'react-router-dom';
const App = () => { const App = () => {
return ( return (
@@ -15,19 +11,9 @@ const App = () => {
<Header /> <Header />
<div className="ph3 pv1 background-gray"> <div className="ph3 pv1 background-gray">
<Switch> <Switch>
<Route exact path="/" component={AppointmentList} /> <Route exact path="/" component={ProductList} />
<Route {/* <Route exact path="/" component={AppointmentList} /> */}
exact {/* <Route exact path="/create" component={CreateAppointment} /> */}
path="/create"
component={CreateAppointment}
/>
<Route exact path="/login" component={Login} />
<Route exact path="/search" component={Search} />
<Route
exact
path="/new/:page"
component={AppointmentList}
/>
</Switch> </Switch>
</div> </div>
</div> </div>
@@ -35,3 +21,42 @@ const App = () => {
}; };
export default App; export default App;
// // import logo from './../logo.svg';
// // import './../styles/App.css';
// import React, { Component } from 'react';
// import AppointmentList from './AppointmentList';
// import CreateAppointment from './CreateAppointment'
// // import Header from './Header';
// import Login from './Login'
// import Search from './Search';
// import { Redirect, Route, Switch } from 'react-router-dom';
// const App = () => {
// return (
// <div className="center w85">
// <Header />
// <div className="ph3 pv1 background-gray">
// <Switch>
// <Route exact path="/" component={AppointmentList} />
// <Route
// exact
// path="/create"
// component={CreateAppointment}
// />
// <Route exact path="/login" component={Login} />
// <Route exact path="/search" component={Search} />
// <Route
// exact
// path="/new/:page"
// component={AppointmentList}
// />
// </Switch>
// </div>
// </div>
// );
// };
// export default App;

View File

@@ -6,56 +6,56 @@ import { useQuery, gql } from '@apollo/client';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
export const FEED_QUERY = gql` export const FEED_QUERY = gql`
query FeedQuery( query AppointmentManyQuery(
$take: Int $take: Int
$skip: Int $skip: Int
$orderBy: AppointmentOrderByInput $orderBy: AppointmentOrderByInput
) { ) {
feed(take: $take, skip: $skip, orderBy: $orderBy) { appointmentMany(take: $take, skip: $skip, orderBy: $orderBy) {
id id
appointments { appointments {
id id
createdAt createdAt
title title
start # start
end # end
description description
createdBy { # createdBy {
id # id
name # name
} # }
follows { # follows {
id # id
user { # user {
id # id
} # }
} # }
} }
count count
} }
} }
`; `;
const NEW_APPOINTMENTS_SUBSCRIPTION = gql` // const NEW_APPOINTMENTS_SUBSCRIPTION = gql`
subscription { // subscription {
newAppointment { // newAppointment {
id // id
url // url
description // description
createdAt // createdAt
createdBy { // createdBy {
id // id
name // name
} // }
follows { // follows {
id // id
user { // user {
id // id
} // }
} // }
} // }
} // }
`; // `;
const getQueryVariables = (isNewPage, page) => { const getQueryVariables = (isNewPage, page) => {
const skip = isNewPage ? (page - 1) * APPOINTMENTS_PER_PAGE : 0; const skip = isNewPage ? (page - 1) * APPOINTMENTS_PER_PAGE : 0;
@@ -102,25 +102,25 @@ const AppointmentList = () => {
return rankedAppointments; return rankedAppointments;
}; };
subscribeToMore({ // subscribeToMore({
document: NEW_APPOINTMENTS_SUBSCRIPTION, // document: NEW_APPOINTMENTS_SUBSCRIPTION,
updateQuery: (prev, { subscriptionData }) => { // updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev; // if (!subscriptionData.data) return prev;
const newAppointment = subscriptionData.data.newAppointment; // const newAppointment = subscriptionData.data.newAppointment;
const exists = prev.feed.appointments.find( // const exists = prev.feed.appointments.find(
({ id }) => id === newAppointment.id // ({ id }) => id === newAppointment.id
); // );
if (exists) return prev; // if (exists) return prev;
return Object.assign({}, prev, { // return Object.assign({}, prev, {
feed: { // feed: {
appointments: [newAppointment, ...prev.feed.appointments], // appointments: [newAppointment, ...prev.feed.appointments],
count: prev.feed.appointments.length + 1, // count: prev.feed.appointments.length + 1,
__typename: prev.feed.__typename // __typename: prev.feed.__typename
} // }
}); // });
} // }
}); // });
return ( return (
<> <>

View File

@@ -1,11 +1,9 @@
import React from 'react'; import React from 'react';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { Link } from 'react-router-dom'; import { Link, withRouter } from 'react-router-dom';
import { AUTH_TOKEN } from '../constants';
const Header = () => { const Header = () => {
const history = useHistory(); const history = useHistory();
const authToken = localStorage.getItem(AUTH_TOKEN);
return ( return (
<div className="flex pa1 justify-between nowrap orange"> <div className="flex pa1 justify-between nowrap orange">
<div className="flex flex-fixed black"> <div className="flex flex-fixed black">
@@ -14,44 +12,12 @@ const Header = () => {
new new
</Link> </Link>
<div className="ml1">|</div> <div className="ml1">|</div>
<Link to="/top" className="ml1 no-underline black"> <Link
top to="/create"
</Link> className="ml1 no-underline black"
<div className="ml1">|</div> >
<Link to="/search" className="ml1 no-underline black"> submit
search </Link>
</Link>
{authToken && (
<div className="flex">
<div className="ml1">|</div>
<Link
to="/create"
className="ml1 no-underline black"
>
submit
</Link>
</div>
)}
</div>
<div className="flex flex-fixed">
{authToken ? (
<div
className="ml1 pointer black"
onClick={() => {
localStorage.removeItem(AUTH_TOKEN);
history.push(`/`);
}}
>
logout
</div>
) : (
<Link
to="/login"
className="ml1 no-underline black"
>
login
</Link>
)}
</div> </div>
</div> </div>
); );

View File

@@ -0,0 +1,14 @@
import React from 'react';
const Product = (props) => {
const { product } = props;
return (
<div>
<div>
<b>{product.title}</b>: only {product.qty}!
</div>
</div>
);
};
export default Product;

View File

@@ -0,0 +1,29 @@
import React from 'react';
import Product from './Product';
import { useQuery, gql } from '@apollo/client';
const FEED_QUERY = gql`
{
allProducts{
title
qty
}
}
`;
const ProductList = () => {
const { data } = useQuery(FEED_QUERY);
console.log("Fah!", data);
return (
<div>
{data.allProducts.map((product) => (
<Product key={product.id} product={product} />
))}
</div>
);
};
export default ProductList;

View File

@@ -52,10 +52,10 @@ const Search = () => {
OK OK
</button> </button>
</div> </div>
{data && {/* {data &&
data.feed.appointments.map((appointment, index) => ( data.feed.appointments.map((appointment, index) => (
<Link key={appointment.id} link={appointment} index={index} /> <Link key={appointment.id} link={appointment} index={index} />
))} ))} */}
</> </>
); );
}; };

View File

@@ -2,6 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import './styles/index.css'; import './styles/index.css';
import App from './components/App'; import App from './components/App';
import { BrowserRouter } from 'react-router-dom';
// import * as serviceWorker from './serviceWorker'; // import * as serviceWorker from './serviceWorker';
// 1 // 1
@@ -14,7 +15,7 @@ import {
// 2 // 2
const httpLink = createHttpLink({ const httpLink = createHttpLink({
uri: 'http://localhost:4000' uri: 'http://localhost:5000/graphql'
}); });
// 3 // 3
@@ -25,9 +26,11 @@ const client = new ApolloClient({
// 4 // 4
ReactDOM.render( ReactDOM.render(
<ApolloProvider client={client}> <BrowserRouter>
<App /> <ApolloProvider client={client}>
</ApolloProvider>, <App />
</ApolloProvider>
</BrowserRouter>,
document.getElementById('root') document.getElementById('root')
); );
// serviceWorker.unregister(); // serviceWorker.unregister();

View File

@@ -7,18 +7,20 @@ import schema from './schema.js';
import './utils/db.js'; import './utils/db.js';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import cors from 'cors';
const moduleURL = new URL(import.meta.url); const moduleURL = new URL(import.meta.url);
const __dirname = path.dirname(moduleURL.pathname); const __dirname = path.dirname(moduleURL.pathname);
const app = express(); const app = express();
const pubsub = new PubSub(); const pubsub = new PubSub();
const PORT = 4000;
dotenv.config(); dotenv.config();
app.use(cors());
app.get('/', (req, res) => { app.get('/', (req, res) => {
res.json({ res.json({
msg: 'Welcome to GraphQL' msg: 'GraphQL home!'
}) })
}); });
@@ -28,32 +30,33 @@ app.use('/graphql', graphqlHTTP({
})); }));
const server = new ApolloServer({ const server = new ApolloServer({
typeDefs: fs.readFileSync( // typeDefs: fs.readFileSync(
path.join(__dirname, 'schema.graphql'), // path.join(__dirname, 'schema.graphql'),
'utf8' // 'utf8'
), // ),
schema,
cors: true, cors: true,
playground: process.env.NODE_ENV === 'development' ? true : false, playground: process.env.NODE_ENV === 'development' ? true : false,
context: async ({ req }) => { // context: async ({ req }) => {
// if (!db) { // // if (!db) {
// try { // // try {
// if (!dbClient.isConnected()) await dbClient.connect() // // if (!dbClient.isConnected()) await dbClient.connect()
// mongo = dbClient.db('Calendar') // database name // // mongo = dbClient.db('Calendar') // database name
// console.log(db); // // console.log(db);
// } catch (e) { // // } catch (e) {
// console.log('--->error while connecting with graphql context (db)', e) // // console.log('--->error while connecting with graphql context (db)', e)
// } // // }
return { // return {
...req, // ...req,
mongoose, // mongoose,
// pubsub, // pubsub,
// userId: // userId:
// req && req.headers.authorization // req && req.headers.authorization
// ? getUserId(req) // ? getUserId(req)
// : null // : null
} // }
}, // },
// subscriptions: { // subscriptions: {
// onConnect: (connectionParams) => { // onConnect: (connectionParams) => {
// if (connectionParams.authToken) { // if (connectionParams.authToken) {

View File

@@ -1,41 +1,38 @@
import Product from './models/product.js'; import Product from './models/product.js';
// import User from './resolvers/User.js';
// import Appointment from './resolvers/Appointment.js';
// import Follow from './resolvers/Follow.js';
// import Query from './resolvers/Query.js';
// import Mutation from './resolvers/Mutation.js';
// import Subscription from './resolvers/Subscription.js';
export const resolvers = { export const resolvers = {
Query: { Query: {
async allProducts() { async allProducts() {
return await Product.find(); const products = await Product.find();
console.log("Tah!", products);
return products;
// return {
// products
// };
},
},
Mutation: {
async createProduct(root, {
input
}) {
return await Product.create(input);
},
async updateProduct(root, {
_id,
input
}) {
return await Product.findOneAndUpdate({
_id
}, input, {
new: true
})
},
async deleteProduct(root, {
_id
}) {
return await Product.findOneAndRemove({
_id
});
}, },
// async feed(parent, args, context, info) {
// const where = args.filter
// ? {
// OR: [
// { title: { contains: args.filter } },
// { description: { contains: args.filter } }
// ]
// }
// : {};
// console.log(context.mongo);
// const appointments = await context.mongo.appointment.findMany({
// where,
// skip: args.skip,
// take: args.take,
// orderBy: args.orderBy
// });
// const count = await context.mongo.appointment.count({ where });
// return {
// id: 'main-feed',
// appointments,
// count
// };
// }
} }
}; };

View File

@@ -7,7 +7,7 @@ type Query {
orderBy: AppointmentOrderByInput orderBy: AppointmentOrderByInput
): Feed! ): Feed!
allProducts: [Product] allProducts: [Product]
# users: [User!]! users: [User!]!
} }
type Feed { type Feed {
@@ -22,7 +22,17 @@ type Mutation {
description: String!, description: String!,
start: DateTime!, start: DateTime!,
end: DateTime!, end: DateTime!,
): Appointment! ): Appointment!
createProduct(
input: ProductInput
) : Product
updateProduct(
_id: ID!,
input: ProductInput
): Product
deleteProduct(
_id: ID!
) : Product
signup( signup(
email: String! email: String!
password: String! password: String!
@@ -68,7 +78,7 @@ type Appointment {
type Product { type Product {
id: ID! id: ID!
title: String! title: String!
qty: Integer qty: Int
} }
type Follow { type Follow {
@@ -77,6 +87,12 @@ type Follow {
user: User! user: User!
} }
input ProductInput {
title: String!
qty: Int
}
input AppointmentOrderByInput { input AppointmentOrderByInput {
description: Sort description: Sort
url: Sort url: Sort
@@ -88,5 +104,4 @@ enum Sort {
desc desc
} }
scalar Integer
scalar DateTime scalar DateTime

View File

@@ -1,45 +1,54 @@
import {
makeExecutableSchema
} from 'graphql-tools';
import {
resolvers
} from './resolvers.js';
import fs from 'fs';
import path from 'path';
const moduleURL = new URL(import.meta.url);
const __dirname = path.dirname(moduleURL.pathname);
const typeDefs = fs.readFileSync(
path.join(__dirname, 'schema.graphql'),
'utf8'
);
const schema = makeExecutableSchema({
typeDefs,
// resolvers
});
export default schema;
// import { // import {
// makeExecutableSchema // makeExecutableSchema
// } from 'graphql-tools'; // } from 'graphql-tools';
// import { // import {
// resolvers // resolvers
// } from './resolvers.js'; // } from './resolvers.js';
// const typeDefs = `
// type Product { // import fs from 'fs';
// _id: ID! // import path from 'path';
// title: String!
// qty: Int // const moduleURL = new URL(import.meta.url);
// } // const __dirname = path.dirname(moduleURL.pathname);
// type Query {
// allProducts: [Product] // const typeDefs = fs.readFileSync(
// } // path.join(__dirname, 'schema.graphql'),
// `; // 'utf8'
// );
// const schema = makeExecutableSchema({ // const schema = makeExecutableSchema({
// typeDefs, // typeDefs,
// resolvers // // resolvers
// }); // });
// export default schema; // export default schema;
import {
makeExecutableSchema
} from 'graphql-tools';
import {
resolvers
} from './resolvers.js';
const typeDefs = `
type Product {
_id: ID!
title: String!
qty: Int
}
type Query {
allProducts: [Product]
}
input ProductInput {
title: String!
qty: Int
}
type Mutation {
createProduct(input: ProductInput) : Product
updateProduct(_id: ID!, input: ProductInput): Product
deleteProduct(_id: ID!) : Product
}
`;
const schema = makeExecutableSchema({
typeDefs,
resolvers
});
export default schema;

View File

@@ -1,20 +0,0 @@
import { SchemaComposer } from 'graphql-compose';
import db from '../utils/db.js';
const schemaComposer = new SchemaComposer();
import { UserQuery, UserMutation } from './user.js';
import { AppointmentQuery, AppointmentMutation } from './appointment.js';
schemaComposer.Query.addFields({
...UserQuery,
...AppointmentQuery,
});
schemaComposer.Mutation.addFields({
...UserMutation,
...AppointmentMutation,
});
export default schemaComposer.buildSchema();