add .graphqlconfig, fix typo in .prettierrc filename, add a new lib - auth
This commit is contained in:
parent
0ea3eb8b07
commit
521286cfcc
|
@ -21,3 +21,5 @@
|
|||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
remote-schema.graphql
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "Zdam Egzamin Zawodowy",
|
||||
"schemaPath": "remote-schema.graphql",
|
||||
"extensions": {
|
||||
"endpoints": {
|
||||
"Default GraphQL Endpoint": {
|
||||
"url": "http://localhost:8080/graphql",
|
||||
"headers": {
|
||||
"user-agent": "JS GraphQL"
|
||||
},
|
||||
"introspect": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@
|
|||
"@types/apollo-upload-client": "^14.1.0",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"babel-plugin-transform-imports": "^2.0.0",
|
||||
"babel-plugin-transform-modules": "^0.1.1",
|
||||
"customize-cra": "^1.0.0",
|
||||
"prettier": "^2.2.1",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
declare enum UserRole {
|
||||
Admin = "admin",
|
||||
User = "user",
|
||||
}
|
|
@ -1,9 +1,27 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import App from "./features/App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { MuiThemeProvider } from '@material-ui/core';
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import App from './features/App';
|
||||
import { AuthProvider } from './libs/auth';
|
||||
import TokenStorage from './libs/tokenstorage/TokenStorage';
|
||||
import createClient from './libs/graphql/createClient';
|
||||
import { API_URI } from './config/api';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
const tokenStorage = new TokenStorage();
|
||||
|
||||
ReactDOM.render(
|
||||
<BrowserRouter>
|
||||
<ApolloProvider client={createClient(API_URI, tokenStorage)}>
|
||||
<AuthProvider tokenStorage={tokenStorage}>
|
||||
<App />
|
||||
</AuthProvider>
|
||||
</ApolloProvider>
|
||||
</BrowserRouter>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
import React, { useMemo, useState, useEffect } from 'react';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { isFunction } from 'lodash';
|
||||
import { context as Context } from './context';
|
||||
import { AuthContext, User } from './types';
|
||||
import TokenStorage from '../tokenstorage/TokenStorage';
|
||||
import { QUERY_ME } from './queries';
|
||||
import { MUTATION_SIGN_IN } from './mutations';
|
||||
|
||||
export interface AuthProviderProps {
|
||||
tokenStorage?: TokenStorage;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
type MeQueryResult = {
|
||||
me: User | null;
|
||||
};
|
||||
|
||||
type SignInMutationResult = {
|
||||
token: string;
|
||||
user: User;
|
||||
};
|
||||
|
||||
type SignInMutationVariables = {
|
||||
email: string;
|
||||
staySignedIn: boolean;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export function AuthProvider(props: AuthProviderProps) {
|
||||
const client = useApolloClient();
|
||||
const [user, setUser] = useState<AuthContext['user']>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const tokenStorage = useMemo(() => {
|
||||
if (props.tokenStorage) {
|
||||
return props.tokenStorage;
|
||||
}
|
||||
return new TokenStorage();
|
||||
}, [props.tokenStorage]);
|
||||
|
||||
useEffect(() => {
|
||||
loadUser();
|
||||
}, []);
|
||||
|
||||
const loadUser = async () => {
|
||||
if (tokenStorage.token) {
|
||||
try {
|
||||
const result = await client.query<MeQueryResult>({
|
||||
query: QUERY_ME,
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
if (result.data.me) {
|
||||
setUser(result.data.me);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const signIn: AuthContext['signIn'] = async (
|
||||
email: string,
|
||||
password: string,
|
||||
staySignedIn: boolean,
|
||||
validate?: (user: User) => boolean
|
||||
) => {
|
||||
const result = await client.mutate<
|
||||
SignInMutationResult,
|
||||
SignInMutationVariables
|
||||
>({
|
||||
mutation: MUTATION_SIGN_IN,
|
||||
variables: {
|
||||
email,
|
||||
password,
|
||||
staySignedIn,
|
||||
},
|
||||
});
|
||||
|
||||
if (result.data?.user) {
|
||||
if (isFunction(validate) && !validate(result.data?.user)) {
|
||||
return null;
|
||||
}
|
||||
tokenStorage.setToken(result.data.token);
|
||||
setUser(result.data.user);
|
||||
client.writeQuery<MeQueryResult>({
|
||||
query: QUERY_ME,
|
||||
data: {
|
||||
me: result.data.user,
|
||||
},
|
||||
});
|
||||
return result.data.user;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const signOut = () => {
|
||||
return client.clearStore().then(() => {
|
||||
tokenStorage.setToken('');
|
||||
setUser(null);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Context.Provider
|
||||
value={{
|
||||
user,
|
||||
tokenStorage,
|
||||
signIn,
|
||||
signOut,
|
||||
loading,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</Context.Provider>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import React from 'react';
|
||||
import { AuthContext } from './types';
|
||||
import TokenStorage from '../tokenstorage/TokenStorage';
|
||||
|
||||
const ctx = React.createContext<AuthContext>({
|
||||
tokenStorage: new TokenStorage(),
|
||||
signIn: () => new Promise(resolve => resolve(null)),
|
||||
signOut: () => new Promise(resolve => resolve()),
|
||||
loading: true,
|
||||
user: null,
|
||||
});
|
||||
ctx.displayName = 'AuthContext';
|
||||
|
||||
const useAuth = (): AuthContext => {
|
||||
return React.useContext(ctx);
|
||||
};
|
||||
|
||||
export { ctx as context, useAuth };
|
|
@ -0,0 +1,5 @@
|
|||
export * from './context';
|
||||
export * from './mutations';
|
||||
export * from './Provider';
|
||||
export * from './queries';
|
||||
export * from './types';
|
|
@ -0,0 +1,19 @@
|
|||
import { gql } from "@apollo/client";
|
||||
|
||||
export const MUTATION_SIGN_IN = gql`
|
||||
mutation signIn(
|
||||
$email: String!
|
||||
$password: String!
|
||||
$staySignedIn: Boolean!
|
||||
) {
|
||||
signIn(email: $email, password: $password, staySignedIn: $staySignedIn) {
|
||||
token
|
||||
user {
|
||||
id
|
||||
displayName
|
||||
email
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,12 @@
|
|||
import { gql } from "@apollo/client";
|
||||
|
||||
export const QUERY_ME = gql`
|
||||
query {
|
||||
me {
|
||||
id
|
||||
displayName
|
||||
role
|
||||
email
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,21 @@
|
|||
import TokenStorage from '../tokenstorage/TokenStorage';
|
||||
|
||||
export type User = {
|
||||
id: number;
|
||||
displayName: string;
|
||||
role: UserRole;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export interface AuthContext {
|
||||
user: User | null;
|
||||
tokenStorage: TokenStorage;
|
||||
signIn: (
|
||||
email: string,
|
||||
password: string,
|
||||
staySignedIn: boolean,
|
||||
validate?: (user: User) => boolean
|
||||
) => Promise<User | null>;
|
||||
signOut: () => Promise<void>;
|
||||
loading: boolean;
|
||||
}
|
43
yarn.lock
43
yarn.lock
|
@ -1157,6 +1157,15 @@
|
|||
lodash "^4.17.19"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.4":
|
||||
version "7.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80"
|
||||
integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.12.11"
|
||||
lodash "^4.17.19"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
|
@ -2829,6 +2838,14 @@ babel-plugin-syntax-object-rest-spread@^6.8.0:
|
|||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
|
||||
integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=
|
||||
|
||||
babel-plugin-transform-imports@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-imports/-/babel-plugin-transform-imports-2.0.0.tgz#9e5f49f751a9d34ba8f4bb988c7e48ed2419c6b6"
|
||||
integrity sha512-65ewumYJ85QiXdcB/jmiU0y0jg6eL6CdnDqQAqQ8JMOKh1E52VPG3NJzbVKWcgovUR5GBH8IWpCXQ7I8Q3wjgw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.4"
|
||||
is-valid-path "^0.1.1"
|
||||
|
||||
babel-plugin-transform-modules@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-modules/-/babel-plugin-transform-modules-0.1.1.tgz#2a72ced69d85613d953196ae9a86d39f19fd7933"
|
||||
|
@ -6229,6 +6246,11 @@ is-extendable@^1.0.1:
|
|||
dependencies:
|
||||
is-plain-object "^2.0.4"
|
||||
|
||||
is-extglob@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
|
||||
integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
|
||||
|
||||
is-extglob@^2.1.0, is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
|
@ -6249,6 +6271,13 @@ is-generator-fn@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
|
||||
integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
|
||||
|
||||
is-glob@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
|
||||
integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
|
||||
dependencies:
|
||||
is-extglob "^1.0.0"
|
||||
|
||||
is-glob@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
|
||||
|
@ -6268,6 +6297,13 @@ is-in-browser@^1.0.2, is-in-browser@^1.1.3:
|
|||
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
|
||||
integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=
|
||||
|
||||
is-invalid-path@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-invalid-path/-/is-invalid-path-0.1.0.tgz#307a855b3cf1a938b44ea70d2c61106053714f34"
|
||||
integrity sha1-MHqFWzzxqTi0TqcNLGEQYFNxTzQ=
|
||||
dependencies:
|
||||
is-glob "^2.0.0"
|
||||
|
||||
is-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
|
||||
|
@ -6393,6 +6429,13 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
|
||||
is-valid-path@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-valid-path/-/is-valid-path-0.1.1.tgz#110f9ff74c37f663e1ec7915eb451f2db93ac9df"
|
||||
integrity sha1-EQ+f90w39mPh7HkV60UfLbk6yd8=
|
||||
dependencies:
|
||||
is-invalid-path "^0.1.0"
|
||||
|
||||
is-windows@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
||||
|
|
Reference in New Issue