Skip to content

Commit

Permalink
Updated Meetup demo to use Apollo hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
Vultraz committed Feb 24, 2020
1 parent 1910ed3 commit 1b1d2cd
Show file tree
Hide file tree
Showing 15 changed files with 515 additions and 545 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-phones-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystonejs/demo-project-meetup': patch
---

Updated Meetup demo to use Apollo hooks.
4 changes: 3 additions & 1 deletion demo-projects/meetup/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"start": "cross-env NODE_ENV=production keystone start"
},
"dependencies": {
"@apollo/react-hoc": "^3.1.3",
"@apollo/react-hooks": "^3.1.3",
"@apollo/react-ssr": "3.1.3",
"@emotion/core": "^10.0.27",
"@keystonejs/adapter-mongoose": "^5.2.0",
"@keystonejs/app-admin-ui": "^5.8.0",
Expand Down Expand Up @@ -42,7 +45,6 @@
"next": "^9.2.0",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-apollo": "^3.1.3",
"react-dom": "^16.12.0",
"react-toast-notifications": "^2.3.0",
"react-use-form-state": "^0.12.0",
Expand Down
2 changes: 1 addition & 1 deletion demo-projects/meetup/site/components/AvatarUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { jsx } from '@emotion/core';
import { useState } from 'react';
import PropTypes from 'prop-types';
import gql from 'graphql-tag';
import { useQuery, useMutation } from 'react-apollo';
import { useQuery, useMutation } from '@apollo/react-hooks';
import { useToasts } from 'react-toast-notifications';
import { Avatar } from './Avatar';

Expand Down
172 changes: 86 additions & 86 deletions demo-projects/meetup/site/components/Rsvp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @jsx jsx */
import { Mutation, Query } from 'react-apollo';
import { useMutation, useQuery } from '@apollo/react-hooks';
import { jsx } from '@emotion/core';

import { Button as ButtonPrimitive, CheckmarkIcon, Loading } from '../primitives';
Expand Down Expand Up @@ -28,6 +28,24 @@ const Rsvp = ({ children, event, text, themeColor }) => {
const eventId = event.id;
const isPast = new Date() > new Date(event.startTime);

const { data, loading: loadingData, error } = useQuery(GET_RSVPS, {
variables: { event: eventId, user: user.id },
});

const refetch = () => [
{
query: GET_RSVPS,
variables: { event: eventId, user: user.id },
},
];

const [updateRsvp, { error: mutationError, loading: mutationLoading }] = useMutation(
hasResponded ? UPDATE_RSVP : ADD_RSVP,
{
refetchQueries: refetch,
}
);

if (isLoading) {
return null;
}
Expand All @@ -51,91 +69,73 @@ const Rsvp = ({ children, event, text, themeColor }) => {
});
}

return (
<Query query={GET_RSVPS} variables={{ event: eventId, user: user.id }}>
{({ data, loading: loadingData, error }) => {
if (error) {
console.error(error);
return null;
}

if (loadingData) {
return children({
component: (
<ButtonWrapper>
<span css={{ marginRight: '0.5em', flex: 1 }}>{text}</span>
<Loading size="xsmall" color={themeColor} />
</ButtonWrapper>
),
});
}

const { userRsvps, eventRsvps, event } = data;
const userResponse = userRsvps && userRsvps[0];
const hasResponded = Boolean(userResponse);
const { okay, message } = validateRsvp({ userRsvps, eventRsvps, event });

if (!okay) {
return children({ message });
}

const refetch = () => [
{
query: GET_RSVPS,
variables: { event: eventId, user: user.id },
},
];

return (
<Mutation mutation={hasResponded ? UPDATE_RSVP : ADD_RSVP} refetchQueries={refetch}>
{(updateRsvp, { error: mutationError, loading: mutationLoading }) => {
if (mutationError) {
return children({ message: mutationError.message });
}

const doRespond = status =>
updateRsvp({
variables: {
rsvp: hasResponded ? userResponse.id : null,
event: eventId,
user: user.id,
status,
},
});
const respondYes = () => doRespond('yes');
const respondNo = () => doRespond('no');

const isGoing = hasResponded ? userResponse.status === 'yes' : false;

return children({
component: (
<ButtonWrapper>
<span css={{ marginRight: '0.5em', flex: 1 }}>{text}</span>
<Button
disabled={mutationLoading || isGoing}
isSelected={hasResponded && isGoing}
background={themeColor}
onClick={respondYes}
>
Yes
</Button>
<Button
disabled={mutationLoading || !isGoing}
isSelected={hasResponded && !isGoing}
background={themeColor}
onClick={respondNo}
>
No
</Button>
</ButtonWrapper>
),
});
}}
</Mutation>
);
}}
</Query>
);
if (error) {
console.error(error);
return null;
}

if (loadingData) {
return children({
component: (
<ButtonWrapper>
<span css={{ marginRight: '0.5em', flex: 1 }}>{text}</span>
<Loading size="xsmall" color={themeColor} />
</ButtonWrapper>
),
});
}

// TODO: is this event the same as the event passed to this component?
const { userRsvps, eventRsvps, event: eventName } = data;
const userResponse = userRsvps && userRsvps[0];
const hasResponded = Boolean(userResponse);
const { okay, message } = validateRsvp({ userRsvps, eventRsvps, eventName });

if (!okay) {
return children({ message });
}

if (mutationError) {
return children({ message: mutationError.message });
}

const doRespond = status =>
updateRsvp({
variables: {
rsvp: hasResponded ? userResponse.id : null,
event: eventId,
user: user.id,
status,
},
});
const respondYes = () => doRespond('yes');
const respondNo = () => doRespond('no');

const isGoing = hasResponded ? userResponse.status === 'yes' : false;

return children({
component: (
<ButtonWrapper>
<span css={{ marginRight: '0.5em', flex: 1 }}>{text}</span>
<Button
disabled={mutationLoading || isGoing}
isSelected={hasResponded && isGoing}
background={themeColor}
onClick={respondYes}
>
Yes
</Button>
<Button
disabled={mutationLoading || !isGoing}
isSelected={hasResponded && !isGoing}
background={themeColor}
onClick={respondNo}
>
No
</Button>
</ButtonWrapper>
),
});
};

Rsvp.defaultProps = {
Expand Down
100 changes: 49 additions & 51 deletions demo-projects/meetup/site/components/auth/forgotPassword.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @jsx jsx */

import { useState, useEffect } from 'react';
import { Mutation } from 'react-apollo';
import { useMutation } from '@apollo/react-hooks';
import Router from 'next/router';
import { jsx } from '@emotion/core';
import gql from 'graphql-tag';
Expand All @@ -10,7 +10,7 @@ import { useAuth } from '../../lib/authentication';
import { Button, Field, Group, Label, Link, Input } from '../../primitives/forms';
import { gridSize, colors } from '../../theme';

export const CREATE_FOGOT_PASSWORD_TOKEN = gql`
export const CREATE_FORGOT_PASSWORD_TOKEN = gql`
mutation startPasswordRecovery($email: String!) {
startPasswordRecovery(email: $email) {
id
Expand All @@ -35,61 +35,59 @@ export default ({ onSuccess, onClickSignin }) => {
}
}, [isAuthenticated]);

return (
<Mutation
mutation={CREATE_FOGOT_PASSWORD_TOKEN}
onCompleted={() => {
const [startPasswordRecovery, { error: mutationError, loading }] = useMutation(
CREATE_FORGOT_PASSWORD_TOKEN,
{
onCompleted: () => {
setEmailSent(true);

if (onSuccess && typeof onSuccess === 'function') {
onSuccess();
}
}}
>
{(startPasswordRecovery, { error: mutationError, loading }) => {
return (
<>
{mutationError && (
<p css={{ color: colors.red }}>There is no account with the email "{email}"</p>
)}
},
}
);

return (
<>
{mutationError && (
<p css={{ color: colors.red }}>There is no account with the email "{email}"</p>
)}

<form
css={{ marginTop: gridSize * 3 }}
noValidate
onSubmit={handleSubmit(startPasswordRecovery)}
>
<Field>
<Label htmlFor="email">Email</Label>
<Input
required
type="text"
autoFocus
autoComplete="email"
placeholder="you@awesome.com"
disabled={isAuthenticated}
value={email}
onChange={e => setEmail(e.target.value)}
/>
</Field>
<form
css={{ marginTop: gridSize * 3 }}
noValidate
onSubmit={handleSubmit(startPasswordRecovery)}
>
<Field>
<Label htmlFor="email">Email</Label>
<Input
required
type="text"
autoFocus
autoComplete="email"
placeholder="you@awesome.com"
disabled={isAuthenticated}
value={email}
onChange={e => setEmail(e.target.value)}
/>
</Field>

<Group>
{loading ? (
<Button disabled>Sending email...</Button>
) : emailSent ? (
<Button disabled css={{ background: colors.greyLight, color: colors.greyMedium }}>
Email sent
</Button>
) : (
<Button type="submit">Send</Button>
)}
<Link href="/signin" onClick={onClickSignin}>
Sign in
</Link>
</Group>
</form>
</>
);
}}
</Mutation>
<Group>
{loading ? (
<Button disabled>Sending email...</Button>
) : emailSent ? (
<Button disabled css={{ background: colors.greyLight, color: colors.greyMedium }}>
Email sent
</Button>
) : (
<Button type="submit">Send</Button>
)}
<Link href="/signin" onClick={onClickSignin}>
Sign in
</Link>
</Group>
</form>
</>
);
};
Loading

0 comments on commit 1b1d2cd

Please sign in to comment.