mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-13 22:37:14 +10:00
Merge branch 'develop' into develop
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
"plugin:jest/style",
|
||||
"prettier"
|
||||
],
|
||||
"plugins": ["jest", "prettier"],
|
||||
"plugins": ["jest", "prettier", "sort-imports-es6-autofix"],
|
||||
"rules": {
|
||||
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
|
||||
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { delay } from '../../src/utils/index';
|
||||
|
||||
const ReachRouter = jest.requireActual('@reach/router');
|
||||
|
||||
const defaultDelayInMilliseconds = 100;
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const navigate = async (to, options) => {
|
||||
await delay(defaultDelayInMilliseconds);
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
...ReachRouter,
|
||||
navigate: jest.fn(navigate),
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import FirebaseStub, { AuthConstants } from '../../gatsby-plugin-firebase';
|
||||
|
||||
test('sets current user to anonymous user 1', async () => {
|
||||
await FirebaseStub.auth().signInAnonymously();
|
||||
|
||||
const { currentUser } = FirebaseStub.auth();
|
||||
expect(currentUser).toBeTruthy();
|
||||
expect(currentUser.uid).toEqual(AuthConstants.anonymousUser1.uid);
|
||||
});
|
||||
|
||||
test('calls onAuthStateChanged observer with anonymous user 1', async () => {
|
||||
let user = null;
|
||||
let error = null;
|
||||
FirebaseStub.auth().onAuthStateChanged(
|
||||
(_user) => {
|
||||
user = _user;
|
||||
},
|
||||
(_error) => {
|
||||
error = _error;
|
||||
},
|
||||
);
|
||||
|
||||
await FirebaseStub.auth().signInAnonymously();
|
||||
|
||||
expect(user).toBeTruthy();
|
||||
expect(user.uid).toEqual(AuthConstants.anonymousUser1.uid);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
|
||||
test('returns anonymous user 1', async () => {
|
||||
const user = await FirebaseStub.auth().signInAnonymously();
|
||||
|
||||
expect(user).toBeTruthy();
|
||||
expect(user.uid).toEqual(AuthConstants.anonymousUser1.uid);
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import FirebaseStub, { AuthConstants } from '../../gatsby-plugin-firebase';
|
||||
|
||||
describe('with Google auth provider', () => {
|
||||
test('sets current user to Google user 3', async () => {
|
||||
await FirebaseStub.auth().signInWithPopup(
|
||||
new FirebaseStub.auth.GoogleAuthProvider(),
|
||||
);
|
||||
|
||||
const { currentUser } = FirebaseStub.auth();
|
||||
expect(currentUser).toBeTruthy();
|
||||
expect(currentUser.uid).toEqual(AuthConstants.googleUser3.uid);
|
||||
});
|
||||
|
||||
test('sets current user provider data', async () => {
|
||||
const provider = new FirebaseStub.auth.GoogleAuthProvider();
|
||||
await FirebaseStub.auth().signInWithPopup(provider);
|
||||
|
||||
const { currentUser } = FirebaseStub.auth();
|
||||
expect(currentUser).toBeTruthy();
|
||||
expect(currentUser.providerData).toBeTruthy();
|
||||
expect(currentUser.providerData).toHaveLength(1);
|
||||
expect(currentUser.providerData[0].providerId).toEqual(provider.providerId);
|
||||
});
|
||||
|
||||
test('calls onAuthStateChanged observer with Google user 3', async () => {
|
||||
let user = null;
|
||||
let error = null;
|
||||
FirebaseStub.auth().onAuthStateChanged(
|
||||
(_user) => {
|
||||
user = _user;
|
||||
},
|
||||
(_error) => {
|
||||
error = _error;
|
||||
},
|
||||
);
|
||||
|
||||
await FirebaseStub.auth().signInWithPopup(
|
||||
new FirebaseStub.auth.GoogleAuthProvider(),
|
||||
);
|
||||
|
||||
expect(user).toBeTruthy();
|
||||
expect(user.uid).toEqual(AuthConstants.googleUser3.uid);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
|
||||
test('returns Google user 3', async () => {
|
||||
const user = await FirebaseStub.auth().signInWithPopup(
|
||||
new FirebaseStub.auth.GoogleAuthProvider(),
|
||||
);
|
||||
|
||||
expect(user).toBeTruthy();
|
||||
expect(user.uid).toEqual(AuthConstants.googleUser3.uid);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import FirebaseStub from '../../gatsby-plugin-firebase';
|
||||
|
||||
test('sets current user to null', async () => {
|
||||
await FirebaseStub.auth().signInAnonymously();
|
||||
|
||||
await FirebaseStub.auth().signOut();
|
||||
|
||||
const { currentUser } = FirebaseStub.auth();
|
||||
expect(currentUser).toBeNull();
|
||||
});
|
||||
|
||||
test('calls onAuthStateChanged observer with null', async () => {
|
||||
let user = null;
|
||||
let error = null;
|
||||
FirebaseStub.auth().onAuthStateChanged(
|
||||
(_user) => {
|
||||
user = _user;
|
||||
},
|
||||
(_error) => {
|
||||
error = _error;
|
||||
},
|
||||
);
|
||||
await FirebaseStub.auth().signInAnonymously();
|
||||
|
||||
await FirebaseStub.auth().signOut();
|
||||
|
||||
expect(user).toBeNull();
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import FirebaseStub, { AuthConstants } from '../../gatsby-plugin-firebase';
|
||||
import FirebaseStub from '../../gatsby-plugin-firebase';
|
||||
|
||||
test('reuses existing Auth instance', () => {
|
||||
const auth1 = FirebaseStub.auth();
|
||||
@@ -9,32 +9,6 @@ test('reuses existing Auth instance', () => {
|
||||
expect(auth1.uuid).toEqual(auth2.uuid);
|
||||
});
|
||||
|
||||
test('returns anonymous user 1 when signing in anonymously', async () => {
|
||||
const user = await FirebaseStub.auth().signInAnonymously();
|
||||
|
||||
expect(user).toBeTruthy();
|
||||
expect(user).toEqual(AuthConstants.anonymousUser1);
|
||||
});
|
||||
|
||||
test('calls onAuthStateChanged observer with anonymous user 1 when signing in anonymously', async () => {
|
||||
let user = null;
|
||||
let error = null;
|
||||
FirebaseStub.auth().onAuthStateChanged(
|
||||
(_user) => {
|
||||
user = _user;
|
||||
},
|
||||
(_error) => {
|
||||
error = _error;
|
||||
},
|
||||
);
|
||||
|
||||
await FirebaseStub.auth().signInAnonymously();
|
||||
|
||||
expect(user).toBeTruthy();
|
||||
expect(user).toEqual(AuthConstants.anonymousUser1);
|
||||
expect(error).toBeNull();
|
||||
});
|
||||
|
||||
test('onAuthStateChanged unsubscribe removes observer', () => {
|
||||
const observer = () => {};
|
||||
const unsubscribe = FirebaseStub.auth().onAuthStateChanged(observer);
|
||||
@@ -49,3 +23,13 @@ test('onAuthStateChanged unsubscribe removes observer', () => {
|
||||
FirebaseStub.auth().onAuthStateChangedObservers.indexOf(observer),
|
||||
).not.toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('current user delete calls signOut', async () => {
|
||||
const mockSignOut = jest.spyOn(FirebaseStub.auth(), 'signOut');
|
||||
await FirebaseStub.auth().signInAnonymously();
|
||||
const { currentUser } = FirebaseStub.auth();
|
||||
|
||||
await currentUser.delete();
|
||||
|
||||
expect(mockSignOut).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ test('initializing data sets up resumes and users', async () => {
|
||||
const resumesDataSnapshot = await resumesRef.once('value');
|
||||
const resumes = resumesDataSnapshot.val();
|
||||
expect(resumes).toBeTruthy();
|
||||
expect(Object.keys(resumes)).toHaveLength(3);
|
||||
expect(Object.keys(resumes)).toHaveLength(5);
|
||||
const demoStateResume1 = resumes[DatabaseConstants.demoStateResume1Id];
|
||||
expect(demoStateResume1).toBeTruthy();
|
||||
expect(demoStateResume1.id).toEqual(DatabaseConstants.demoStateResume1Id);
|
||||
@@ -33,20 +33,35 @@ test('initializing data sets up resumes and users', async () => {
|
||||
expect(demoStateResume2).toBeTruthy();
|
||||
expect(demoStateResume2.id).toEqual(DatabaseConstants.demoStateResume2Id);
|
||||
expect(demoStateResume2.user).toEqual(DatabaseConstants.user2.uid);
|
||||
const initialStateResume = resumes[DatabaseConstants.initialStateResumeId];
|
||||
expect(initialStateResume).toBeTruthy();
|
||||
expect(initialStateResume.id).toEqual(DatabaseConstants.initialStateResumeId);
|
||||
expect(initialStateResume.user).toEqual(DatabaseConstants.user1.uid);
|
||||
const initialStateResume1 = resumes[DatabaseConstants.initialStateResume1Id];
|
||||
expect(initialStateResume1).toBeTruthy();
|
||||
expect(initialStateResume1.id).toEqual(
|
||||
DatabaseConstants.initialStateResume1Id,
|
||||
);
|
||||
expect(initialStateResume1.user).toEqual(DatabaseConstants.user1.uid);
|
||||
const demoStateResume3 = resumes[DatabaseConstants.demoStateResume3Id];
|
||||
expect(demoStateResume3).toBeTruthy();
|
||||
expect(demoStateResume3.id).toEqual(DatabaseConstants.demoStateResume3Id);
|
||||
expect(demoStateResume3.user).toEqual(DatabaseConstants.user3.uid);
|
||||
const initialStateResume2 = resumes[DatabaseConstants.initialStateResume2Id];
|
||||
expect(initialStateResume2).toBeTruthy();
|
||||
expect(initialStateResume2.id).toEqual(
|
||||
DatabaseConstants.initialStateResume2Id,
|
||||
);
|
||||
expect(initialStateResume2.user).toEqual(DatabaseConstants.user3.uid);
|
||||
|
||||
const usersRef = FirebaseStub.database().ref(DatabaseConstants.usersPath);
|
||||
const usersDataSnapshot = await usersRef.once('value');
|
||||
const users = usersDataSnapshot.val();
|
||||
expect(users).toBeTruthy();
|
||||
expect(Object.keys(users)).toHaveLength(2);
|
||||
expect(Object.keys(users)).toHaveLength(3);
|
||||
const anonymousUser1 = users[DatabaseConstants.user1.uid];
|
||||
expect(anonymousUser1).toBeTruthy();
|
||||
expect(anonymousUser1).toEqual(DatabaseConstants.user1);
|
||||
const anonymousUser2 = users[DatabaseConstants.user2.uid];
|
||||
expect(anonymousUser2).toBeTruthy();
|
||||
expect(anonymousUser2).toEqual(DatabaseConstants.user2);
|
||||
const googleUser3 = users[DatabaseConstants.user3.uid];
|
||||
expect(googleUser3).toBeTruthy();
|
||||
expect(googleUser3).toEqual(DatabaseConstants.user3);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import FirebaseStub from '../../gatsby-plugin-firebase';
|
||||
|
||||
test('reuses existing Functions instance', () => {
|
||||
const functions1 = FirebaseStub.functions();
|
||||
const functions2 = FirebaseStub.functions();
|
||||
|
||||
expect(functions1.uuid).toBeTruthy();
|
||||
expect(functions2.uuid).toBeTruthy();
|
||||
expect(functions1.uuid).toEqual(functions2.uuid);
|
||||
});
|
||||
|
||||
test('deleteUser function returns true', async () => {
|
||||
const deleteUser = FirebaseStub.functions().httpsCallable('deleteUser');
|
||||
|
||||
const result = await deleteUser();
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect(result.data).toEqual(true);
|
||||
});
|
||||
@@ -1,7 +1,10 @@
|
||||
import Auth from './gatsby-plugin-firebase/auth/auth';
|
||||
import Database from './gatsby-plugin-firebase/database/database';
|
||||
import AuthConstants from './gatsby-plugin-firebase/constants/auth';
|
||||
import Database from './gatsby-plugin-firebase/database/database';
|
||||
import DatabaseConstants from './gatsby-plugin-firebase/constants/database';
|
||||
import Functions from './gatsby-plugin-firebase/functions/functions';
|
||||
import FunctionsConstants from './gatsby-plugin-firebase/constants/functions';
|
||||
import GoogleAuthProvider from './gatsby-plugin-firebase/auth/googleAuthProvider';
|
||||
|
||||
class FirebaseStub {
|
||||
static auth() {
|
||||
@@ -11,8 +14,14 @@ class FirebaseStub {
|
||||
static database() {
|
||||
return Database.instance;
|
||||
}
|
||||
|
||||
static functions() {
|
||||
return Functions.instance;
|
||||
}
|
||||
}
|
||||
|
||||
FirebaseStub.auth.GoogleAuthProvider = GoogleAuthProvider;
|
||||
|
||||
FirebaseStub.database.ServerValue = {};
|
||||
Object.defineProperty(FirebaseStub.database.ServerValue, 'TIMESTAMP', {
|
||||
get() {
|
||||
@@ -21,4 +30,4 @@ Object.defineProperty(FirebaseStub.database.ServerValue, 'TIMESTAMP', {
|
||||
});
|
||||
|
||||
export default FirebaseStub;
|
||||
export { AuthConstants, DatabaseConstants };
|
||||
export { AuthConstants, DatabaseConstants, FunctionsConstants };
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import Constants from '../constants/auth';
|
||||
import { delay } from '../../../src/utils/index';
|
||||
import AuthProvider from './authProvider';
|
||||
import Constants from '../constants/auth';
|
||||
import GoogleAuthProvider from './googleAuthProvider';
|
||||
import User from './user';
|
||||
|
||||
const singleton = Symbol('');
|
||||
const singletonEnforcer = Symbol('');
|
||||
@@ -14,6 +17,7 @@ class Auth {
|
||||
}
|
||||
|
||||
this._uuid = uuidv4();
|
||||
this._currentUser = null;
|
||||
this._onAuthStateChangedObservers = [];
|
||||
}
|
||||
|
||||
@@ -25,6 +29,10 @@ class Auth {
|
||||
return this[singleton];
|
||||
}
|
||||
|
||||
get currentUser() {
|
||||
return this._currentUser;
|
||||
}
|
||||
|
||||
get uuid() {
|
||||
return this._uuid;
|
||||
}
|
||||
@@ -46,11 +54,72 @@ class Auth {
|
||||
async signInAnonymously() {
|
||||
const user = Constants.anonymousUser1;
|
||||
|
||||
this._currentUser = new User(
|
||||
user.displayName,
|
||||
user.email,
|
||||
user.providerId,
|
||||
user.uid,
|
||||
user.isAnonymous,
|
||||
this.signOut.bind(this),
|
||||
);
|
||||
|
||||
await delay(Constants.defaultDelayInMilliseconds);
|
||||
|
||||
this.onAuthStateChangedObservers.forEach((observer) => observer(user));
|
||||
this.onAuthStateChangedObservers.forEach((observer) =>
|
||||
observer(this._currentUser),
|
||||
);
|
||||
|
||||
return user;
|
||||
return this._currentUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates with popup.
|
||||
*
|
||||
* @param {AuthProvider} provider The provider to authenticate.
|
||||
*/
|
||||
async signInWithPopup(provider) {
|
||||
if (!provider) {
|
||||
throw new Error('provider must be provided.');
|
||||
} else if (!(provider instanceof AuthProvider)) {
|
||||
throw new Error('provider should be an AuthProvider.');
|
||||
}
|
||||
|
||||
if (!(provider instanceof GoogleAuthProvider)) {
|
||||
throw new Error(
|
||||
`${provider.constructor.name} is currently not supported.`,
|
||||
);
|
||||
}
|
||||
|
||||
const user = Constants.googleUser3;
|
||||
|
||||
this._currentUser = new User(
|
||||
user.displayName,
|
||||
user.email,
|
||||
user.providerId,
|
||||
user.uid,
|
||||
user.isAnonymous,
|
||||
this.signOut.bind(this),
|
||||
);
|
||||
|
||||
await delay(Constants.defaultDelayInMilliseconds);
|
||||
|
||||
this.onAuthStateChangedObservers.forEach((observer) =>
|
||||
observer(this._currentUser),
|
||||
);
|
||||
|
||||
return this._currentUser;
|
||||
}
|
||||
|
||||
async signOut() {
|
||||
if (this._currentUser === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._currentUser = null;
|
||||
|
||||
await delay(Constants.defaultDelayInMilliseconds);
|
||||
|
||||
this.onAuthStateChangedObservers.forEach((observer) => observer(null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
class AuthProvider {
|
||||
/**
|
||||
* Creates a new auth provider.
|
||||
*
|
||||
* @param {string} providerId Provider ID.
|
||||
*/
|
||||
constructor(providerId) {
|
||||
if (!providerId) {
|
||||
throw new Error('providerId must be provided.');
|
||||
} else if (typeof providerId !== 'string') {
|
||||
throw new Error('providerId should be a string.');
|
||||
} else {
|
||||
this._providerId = providerId;
|
||||
}
|
||||
}
|
||||
|
||||
get providerId() {
|
||||
return this._providerId;
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthProvider;
|
||||
@@ -0,0 +1,10 @@
|
||||
import AuthProvider from './authProvider';
|
||||
import Constants from '../constants/auth';
|
||||
|
||||
class GoogleAuthProvider extends AuthProvider {
|
||||
constructor() {
|
||||
super(Constants.googleAuthProviderId);
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleAuthProvider;
|
||||
@@ -0,0 +1,67 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import Constants from '../constants/auth';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import AuthProvider from './authProvider';
|
||||
import UserInfo from './userInfo';
|
||||
import { delay } from '../../../src/utils/index';
|
||||
|
||||
class User extends UserInfo {
|
||||
/**
|
||||
* Creates a new user.
|
||||
*
|
||||
* @param {string|null} displayName Display name.
|
||||
* @param {string|null} email Email.
|
||||
* @param {string} providerId Auth provider ID.
|
||||
* @param {string} uid The user's unique ID.
|
||||
* @param {boolean} isAnonymous Is anonymous.
|
||||
* @param {function():Promise<void>} deleteUser Delete user callback.
|
||||
*/
|
||||
constructor(displayName, email, providerId, uid, isAnonymous, deleteUser) {
|
||||
super(displayName, email, providerId, uid);
|
||||
|
||||
if (!deleteUser) {
|
||||
throw new Error('deleteUser must be provided.');
|
||||
} else if (typeof deleteUser !== 'function') {
|
||||
throw new Error('deleteUser should be a function.');
|
||||
} else {
|
||||
this._deleteUser = deleteUser;
|
||||
}
|
||||
|
||||
this._isAnonymous = isAnonymous;
|
||||
|
||||
this._providerData = [];
|
||||
if (!isAnonymous) {
|
||||
this._providerData.push(
|
||||
new UserInfo(displayName, email, providerId, uid),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
get isAnonymous() {
|
||||
return this._isAnonymous;
|
||||
}
|
||||
|
||||
get providerData() {
|
||||
return this._providerData;
|
||||
}
|
||||
|
||||
async delete() {
|
||||
await delay(Constants.defaultDelayInMilliseconds);
|
||||
|
||||
await this._deleteUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthenticates the user with popup.
|
||||
*
|
||||
* @param {AuthProvider} provider The provider to authenticate.
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async reauthenticateWithPopup(provider) {
|
||||
await delay(Constants.defaultDelayInMilliseconds);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default User;
|
||||
@@ -0,0 +1,47 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
class UserInfo {
|
||||
/**
|
||||
* Creates a new user profile information.
|
||||
*
|
||||
* @param {string|null} displayName Display name.
|
||||
* @param {string|null} email Email.
|
||||
* @param {string} providerId Auth provider ID.
|
||||
* @param {string} uid The user's unique ID.
|
||||
*/
|
||||
constructor(displayName, email, providerId, uid) {
|
||||
if (!uid) {
|
||||
throw new Error('uid must be provided.');
|
||||
} else if (typeof uid !== 'string') {
|
||||
throw new Error('uid should be a string.');
|
||||
} else {
|
||||
this._uid = uid;
|
||||
}
|
||||
|
||||
if (typeof providerId !== 'string') {
|
||||
throw new Error('providerId should be a string.');
|
||||
} else {
|
||||
this._providerId = providerId;
|
||||
}
|
||||
|
||||
this._displayName = displayName;
|
||||
this._email = email;
|
||||
}
|
||||
|
||||
get displayName() {
|
||||
return this._displayName;
|
||||
}
|
||||
|
||||
get email() {
|
||||
return this._email;
|
||||
}
|
||||
|
||||
get providerId() {
|
||||
return this._providerId;
|
||||
}
|
||||
|
||||
get uid() {
|
||||
return this._uid;
|
||||
}
|
||||
}
|
||||
|
||||
export default UserInfo;
|
||||
@@ -1,22 +1,36 @@
|
||||
const googleAuthProviderId = 'google.com';
|
||||
|
||||
const anonymousUser1 = {
|
||||
displayName: 'Anonymous User 1',
|
||||
email: 'anonymous1@noemail.com',
|
||||
isAnonymous: true,
|
||||
name: 'Anonymous 1',
|
||||
uid: 'anonym123',
|
||||
providerId: '',
|
||||
uid: 'anonym1',
|
||||
};
|
||||
|
||||
const anonymousUser2 = {
|
||||
displayName: 'Anonymous User 2',
|
||||
email: 'anonymous2@noemail.com',
|
||||
isAnonymous: true,
|
||||
name: 'Anonymous 2',
|
||||
uid: 'anonym456',
|
||||
providerId: '',
|
||||
uid: 'anonym2',
|
||||
};
|
||||
|
||||
const googleUser3 = {
|
||||
displayName: 'Google User 3',
|
||||
email: 'google3@noemail.com',
|
||||
isAnonymous: false,
|
||||
providerId: googleAuthProviderId,
|
||||
uid: 'google3',
|
||||
};
|
||||
|
||||
const defaultDelayInMilliseconds = 100;
|
||||
|
||||
class Auth {
|
||||
static get googleAuthProviderId() {
|
||||
return googleAuthProviderId;
|
||||
}
|
||||
|
||||
static get anonymousUser1() {
|
||||
return anonymousUser1;
|
||||
}
|
||||
@@ -25,6 +39,10 @@ class Auth {
|
||||
return anonymousUser2;
|
||||
}
|
||||
|
||||
static get googleUser3() {
|
||||
return googleUser3;
|
||||
}
|
||||
|
||||
static get defaultDelayInMilliseconds() {
|
||||
return defaultDelayInMilliseconds;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ const connectedPath = '.info/connected';
|
||||
|
||||
const demoStateResume1Id = 'demo_1';
|
||||
const demoStateResume2Id = 'demo_2';
|
||||
const initialStateResumeId = 'initst';
|
||||
const demoStateResume3Id = 'demo_3';
|
||||
const initialStateResume1Id = 'init_1';
|
||||
const initialStateResume2Id = 'init_2';
|
||||
|
||||
const user1 = {
|
||||
uid: AuthConstants.anonymousUser1.uid,
|
||||
@@ -19,6 +21,10 @@ const user2 = {
|
||||
uid: AuthConstants.anonymousUser2.uid,
|
||||
isAnonymous: AuthConstants.anonymousUser2.isAnonymous,
|
||||
};
|
||||
const user3 = {
|
||||
uid: AuthConstants.googleUser3.uid,
|
||||
isAnonymous: AuthConstants.googleUser3.isAnonymous,
|
||||
};
|
||||
|
||||
const defaultDelayInMilliseconds = 100;
|
||||
|
||||
@@ -51,8 +57,16 @@ class Database {
|
||||
return demoStateResume2Id;
|
||||
}
|
||||
|
||||
static get initialStateResumeId() {
|
||||
return initialStateResumeId;
|
||||
static get demoStateResume3Id() {
|
||||
return demoStateResume3Id;
|
||||
}
|
||||
|
||||
static get initialStateResume1Id() {
|
||||
return initialStateResume1Id;
|
||||
}
|
||||
|
||||
static get initialStateResume2Id() {
|
||||
return initialStateResume2Id;
|
||||
}
|
||||
|
||||
static get user1() {
|
||||
@@ -63,6 +77,10 @@ class Database {
|
||||
return user2;
|
||||
}
|
||||
|
||||
static get user3() {
|
||||
return user3;
|
||||
}
|
||||
|
||||
static get defaultDelayInMilliseconds() {
|
||||
return defaultDelayInMilliseconds;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
const deleteUserFunctionName = 'deleteUser';
|
||||
|
||||
const defaultDelayInMilliseconds = 100;
|
||||
|
||||
class Functions {
|
||||
static get deleteUserFunctionName() {
|
||||
return deleteUserFunctionName;
|
||||
}
|
||||
|
||||
static get defaultDelayInMilliseconds() {
|
||||
return defaultDelayInMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
export default Functions;
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import DatabaseConstants from '../constants/database';
|
||||
import Reference from './reference';
|
||||
@@ -101,9 +101,9 @@ class Database {
|
||||
|
||||
initializeData() {
|
||||
const resumes = {};
|
||||
const date = new Date('December 15, 2020 11:20:25');
|
||||
|
||||
const demoStateResume1 = readFile('../../../src/data/demoState.json');
|
||||
const date = new Date('December 15, 2020 11:20:25');
|
||||
demoStateResume1.updatedAt = date.valueOf();
|
||||
date.setMonth(date.getMonth() - 2);
|
||||
demoStateResume1.createdAt = date.valueOf();
|
||||
@@ -114,11 +114,24 @@ class Database {
|
||||
demoStateResume2.user = DatabaseConstants.user2.uid;
|
||||
resumes[DatabaseConstants.demoStateResume2Id] = demoStateResume2;
|
||||
|
||||
const initialStateResume = readFile('../../../src/data/initialState.json');
|
||||
initialStateResume.updatedAt = date.valueOf();
|
||||
initialStateResume.createdAt = date.valueOf();
|
||||
initialStateResume.user = DatabaseConstants.user1.uid;
|
||||
resumes[DatabaseConstants.initialStateResumeId] = initialStateResume;
|
||||
const initialStateResume1 = readFile('../../../src/data/initialState.json');
|
||||
initialStateResume1.updatedAt = date.valueOf();
|
||||
initialStateResume1.createdAt = date.valueOf();
|
||||
initialStateResume1.user = DatabaseConstants.user1.uid;
|
||||
resumes[DatabaseConstants.initialStateResume1Id] = initialStateResume1;
|
||||
|
||||
const demoStateResume3 = readFile('../../../src/data/demoState.json');
|
||||
demoStateResume3.updatedAt = date.valueOf();
|
||||
date.setMonth(date.getMonth() - 2);
|
||||
demoStateResume3.createdAt = date.valueOf();
|
||||
demoStateResume3.user = DatabaseConstants.user3.uid;
|
||||
resumes[DatabaseConstants.demoStateResume3Id] = demoStateResume3;
|
||||
|
||||
const initialStateResume2 = readFile('../../../src/data/initialState.json');
|
||||
initialStateResume2.updatedAt = date.valueOf();
|
||||
initialStateResume2.createdAt = date.valueOf();
|
||||
initialStateResume2.user = DatabaseConstants.user3.uid;
|
||||
resumes[DatabaseConstants.initialStateResume2Id] = initialStateResume2;
|
||||
|
||||
Object.keys(resumes).forEach((key) => {
|
||||
const resume = resumes[key];
|
||||
@@ -131,6 +144,7 @@ class Database {
|
||||
const users = {};
|
||||
users[DatabaseConstants.user1.uid] = DatabaseConstants.user1;
|
||||
users[DatabaseConstants.user2.uid] = DatabaseConstants.user2;
|
||||
users[DatabaseConstants.user3.uid] = DatabaseConstants.user3;
|
||||
this._data[DatabaseConstants.usersPath] = users;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import DatabaseConstants from '../constants/database';
|
||||
import DataSnapshot from './dataSnapshot';
|
||||
import { delay } from '../../../src/utils/index';
|
||||
import DataSnapshot from './dataSnapshot';
|
||||
import DatabaseConstants from '../constants/database';
|
||||
|
||||
const parsePath = (path) => {
|
||||
if (!path) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import FunctionsConstants from '../constants/functions';
|
||||
import HttpsCallableResult from './httpsCallableResult';
|
||||
import { delay } from '../../../src/utils/index';
|
||||
|
||||
const singleton = Symbol('');
|
||||
const singletonEnforcer = Symbol('');
|
||||
|
||||
const deleteUser = async () => {
|
||||
await delay(FunctionsConstants.defaultDelayInMilliseconds);
|
||||
|
||||
return new HttpsCallableResult(true);
|
||||
};
|
||||
|
||||
class Functions {
|
||||
constructor(enforcer) {
|
||||
if (enforcer !== singletonEnforcer) {
|
||||
throw new Error('Cannot construct singleton');
|
||||
}
|
||||
|
||||
this._uuid = uuidv4();
|
||||
|
||||
this._httpsCallables = {};
|
||||
this._httpsCallables[
|
||||
FunctionsConstants.deleteUserFunctionName
|
||||
] = deleteUser;
|
||||
}
|
||||
|
||||
static get instance() {
|
||||
if (!this[singleton]) {
|
||||
this[singleton] = new Functions(singletonEnforcer);
|
||||
}
|
||||
|
||||
return this[singleton];
|
||||
}
|
||||
|
||||
get uuid() {
|
||||
return this._uuid;
|
||||
}
|
||||
|
||||
httpsCallable(name) {
|
||||
if (!name) {
|
||||
throw new Error('name must be provided.');
|
||||
} else if (typeof name !== 'string') {
|
||||
throw new Error('name should be a string.');
|
||||
}
|
||||
|
||||
return this._httpsCallables[name];
|
||||
}
|
||||
}
|
||||
|
||||
export default Functions;
|
||||
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
class HttpsCallableResult {
|
||||
constructor(data) {
|
||||
this._uuid = uuidv4();
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
get uuid() {
|
||||
return this._uuid;
|
||||
}
|
||||
}
|
||||
|
||||
export default HttpsCallableResult;
|
||||
+18
-38
@@ -4,24 +4,18 @@ import { delay } from '../src/utils/index';
|
||||
|
||||
const Gatsby = jest.requireActual('gatsby');
|
||||
|
||||
const fluidImageShapes = [
|
||||
{
|
||||
aspectRatio: 2,
|
||||
src: 'test_image.jpg',
|
||||
srcSet: 'some srcSet',
|
||||
srcSetWebp: 'some srcSetWebp',
|
||||
sizes: '(max-width: 600px) 100vw, 600px',
|
||||
base64: 'string_of_base64',
|
||||
const imageData = {
|
||||
images: {
|
||||
fallback: {
|
||||
src: `image_src.jpg`,
|
||||
srcSet: `image_src_set.jpg 1x`,
|
||||
},
|
||||
},
|
||||
{
|
||||
aspectRatio: 3,
|
||||
src: 'test_image_2.jpg',
|
||||
srcSet: 'some other srcSet',
|
||||
srcSetWebp: 'some other srcSetWebp',
|
||||
sizes: '(max-width: 400px) 100vw, 400px',
|
||||
base64: 'string_of_base64',
|
||||
},
|
||||
];
|
||||
layout: `fixed`,
|
||||
width: 1,
|
||||
height: 2,
|
||||
};
|
||||
const childImageSharp = { gatsbyImageData: imageData };
|
||||
|
||||
const useStaticQuery = () => ({
|
||||
site: {
|
||||
@@ -33,39 +27,25 @@ const useStaticQuery = () => ({
|
||||
},
|
||||
},
|
||||
file: {
|
||||
childImageSharp: {
|
||||
fluid: fluidImageShapes[0],
|
||||
},
|
||||
childImageSharp,
|
||||
},
|
||||
onyx: {
|
||||
childImageSharp: {
|
||||
fluid: fluidImageShapes[0],
|
||||
},
|
||||
childImageSharp,
|
||||
},
|
||||
pikachu: {
|
||||
childImageSharp: {
|
||||
fluid: fluidImageShapes[1],
|
||||
},
|
||||
childImageSharp,
|
||||
},
|
||||
gengar: {
|
||||
childImageSharp: {
|
||||
fluid: fluidImageShapes[0],
|
||||
},
|
||||
childImageSharp,
|
||||
},
|
||||
castform: {
|
||||
childImageSharp: {
|
||||
fluid: fluidImageShapes[1],
|
||||
},
|
||||
childImageSharp,
|
||||
},
|
||||
glalie: {
|
||||
childImageSharp: {
|
||||
fluid: fluidImageShapes[0],
|
||||
},
|
||||
childImageSharp,
|
||||
},
|
||||
celebi: {
|
||||
childImageSharp: {
|
||||
fluid: fluidImageShapes[1],
|
||||
},
|
||||
childImageSharp,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Generated
+2508
-56
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,9 @@
|
||||
"logs": "firebase functions:log"
|
||||
},
|
||||
"dependencies": {
|
||||
"firebase-admin": "^9.5.0",
|
||||
"firebase-functions": "^3.13.2",
|
||||
"puppeteer": "8.0.0"
|
||||
"firebase-admin": "^9.9.0",
|
||||
"firebase-functions": "^3.14.1",
|
||||
"puppeteer": "9.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"firebase-functions-test": "^0.2.3"
|
||||
|
||||
+15
-14
@@ -1,17 +1,4 @@
|
||||
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core';
|
||||
import 'animate.css';
|
||||
import 'firebase/analytics';
|
||||
import 'firebase/auth';
|
||||
import 'firebase/database';
|
||||
import 'firebase/functions';
|
||||
import 'firebase/storage';
|
||||
import React from 'react';
|
||||
import { DatabaseProvider } from './src/contexts/DatabaseContext';
|
||||
import { ModalProvider } from './src/contexts/ModalContext';
|
||||
import { ResumeProvider } from './src/contexts/ResumeContext';
|
||||
import { SettingsProvider } from './src/contexts/SettingsContext';
|
||||
import { StorageProvider } from './src/contexts/StorageContext';
|
||||
import { UserProvider } from './src/contexts/UserContext';
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import './src/i18n';
|
||||
import './src/styles/forms.css';
|
||||
import './src/styles/global.css';
|
||||
@@ -19,6 +6,20 @@ import './src/styles/shadows.css';
|
||||
import './src/styles/tailwind.css';
|
||||
import './src/styles/toastify.css';
|
||||
import './src/utils/dayjs';
|
||||
import 'animate.css';
|
||||
import 'firebase/analytics';
|
||||
import 'firebase/auth';
|
||||
import 'firebase/database';
|
||||
import 'firebase/functions';
|
||||
import 'firebase/storage';
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { DatabaseProvider } from './src/contexts/DatabaseContext';
|
||||
import { ModalProvider } from './src/contexts/ModalContext';
|
||||
import { ResumeProvider } from './src/contexts/ResumeContext';
|
||||
import { SettingsProvider } from './src/contexts/SettingsContext';
|
||||
import { StorageProvider } from './src/contexts/StorageContext';
|
||||
import { UserProvider } from './src/contexts/UserContext';
|
||||
|
||||
const theme = createMuiTheme({
|
||||
typography: {
|
||||
|
||||
+2
-2
@@ -1,12 +1,11 @@
|
||||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
flags: { PRESERVE_WEBPACK_CACHE: true },
|
||||
siteMetadata: {
|
||||
title: 'Reactive Resume',
|
||||
siteUrl: 'https://rxresu.me',
|
||||
description: 'A free and open source resume builder.',
|
||||
version: '2.6.8',
|
||||
version: '2.7.0',
|
||||
},
|
||||
plugins: [
|
||||
'gatsby-plugin-react-helmet',
|
||||
@@ -35,6 +34,7 @@ module.exports = {
|
||||
display: 'standalone',
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-image`,
|
||||
`gatsby-plugin-offline`,
|
||||
{
|
||||
resolve: 'gatsby-plugin-webfonts',
|
||||
|
||||
+23
-10
@@ -1,15 +1,28 @@
|
||||
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
|
||||
if (stage === 'build-javascript') {
|
||||
const config = getConfig();
|
||||
const miniCssExtractPlugin = config.plugins.find(
|
||||
(plugin) => plugin.constructor.name === 'MiniCssExtractPlugin',
|
||||
);
|
||||
if (miniCssExtractPlugin) {
|
||||
miniCssExtractPlugin.options.ignoreOrder = true;
|
||||
}
|
||||
actions.replaceWebpackConfig(config);
|
||||
exports.onCreateWebpackConfig = ({ stage, actions, plugins, getConfig }) => {
|
||||
actions.setWebpackConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
path: require.resolve('path-browserify'),
|
||||
},
|
||||
fallback: {
|
||||
fs: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (stage === 'build-javascript' || stage === 'develop') {
|
||||
actions.setWebpackConfig({
|
||||
plugins: [plugins.provide({ process: 'process/browser' })],
|
||||
});
|
||||
}
|
||||
|
||||
const config = getConfig();
|
||||
const miniCssExtractPlugin = config.plugins.find(
|
||||
(plugin) => plugin.constructor.name === 'MiniCssExtractPlugin',
|
||||
);
|
||||
miniCssExtractPlugin && (miniCssExtractPlugin.options.ignoreOrder = true);
|
||||
actions.replaceWebpackConfig(config);
|
||||
|
||||
if (stage === 'build-html') {
|
||||
actions.setWebpackConfig({
|
||||
externals: [/^firebase/],
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@ const babelOptions = {
|
||||
presets: ['babel-preset-gatsby'],
|
||||
};
|
||||
|
||||
module.exports = require('babel-jest').createTransformer(babelOptions);
|
||||
module.exports = require('babel-jest').default.createTransformer(babelOptions);
|
||||
|
||||
+4
-1
@@ -1,3 +1,5 @@
|
||||
const esModules = ['gatsby', 'nanoevents'].join('|');
|
||||
|
||||
module.exports = {
|
||||
testRegex: '/*.test.js$',
|
||||
collectCoverage: true,
|
||||
@@ -26,11 +28,12 @@ module.exports = {
|
||||
'.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': `<rootDir>/__mocks__/file-mock.js`,
|
||||
},
|
||||
testPathIgnorePatterns: [`node_modules`, `\\.cache`],
|
||||
transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`],
|
||||
transformIgnorePatterns: [`node_modules/(?!${esModules})`],
|
||||
globals: {
|
||||
__PATH_PREFIX__: ``,
|
||||
},
|
||||
testURL: `http://localhost`,
|
||||
setupFiles: [`<rootDir>/loadershim.js`],
|
||||
setupFilesAfterEnv: [`<rootDir>/jest.setup.js`],
|
||||
testEnvironment: 'jsdom',
|
||||
};
|
||||
|
||||
Generated
+41771
-12740
File diff suppressed because it is too large
Load Diff
+53
-50
@@ -17,72 +17,75 @@
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.11.3",
|
||||
"@material-ui/core": "^4.11.4",
|
||||
"@reach/router": "^1.3.4",
|
||||
"animate.css": "^4.1.1",
|
||||
"array-move": "^3.0.1",
|
||||
"autoprefixer": "^10.2.4",
|
||||
"classnames": "^2.2.6",
|
||||
"dayjs": "^1.10.4",
|
||||
"dotenv": "^8.2.0",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"classnames": "^2.3.1",
|
||||
"dayjs": "^1.10.5",
|
||||
"dotenv": "^10.0.0",
|
||||
"downloadjs": "^1.4.7",
|
||||
"firebase": "^8.2.7",
|
||||
"formik": "^2.2.6",
|
||||
"gatsby": "^2.32.3",
|
||||
"gatsby-image": "^2.11.0",
|
||||
"gatsby-plugin-create-client-paths": "^2.10.0",
|
||||
"firebase": "^8.6.3",
|
||||
"formik": "^2.2.8",
|
||||
"gatsby": "^3.6.1",
|
||||
"gatsby-plugin-create-client-paths": "^3.6.0",
|
||||
"gatsby-plugin-firebase": "^0.2.0-beta.4",
|
||||
"gatsby-plugin-manifest": "^2.12.0",
|
||||
"gatsby-plugin-material-ui": "^2.1.10",
|
||||
"gatsby-plugin-offline": "^3.10.0",
|
||||
"gatsby-plugin-postcss": "^3.7.0",
|
||||
"gatsby-plugin-react-helmet": "^3.10.0",
|
||||
"gatsby-plugin-sharp": "^2.14.1",
|
||||
"gatsby-plugin-sitemap": "^2.12.0",
|
||||
"gatsby-plugin-webfonts": "^1.1.4",
|
||||
"gatsby-source-filesystem": "^2.11.0",
|
||||
"gatsby-source-gravatar": "^1.0.0",
|
||||
"gatsby-transformer-remark": "^2.16.0",
|
||||
"gatsby-transformer-sharp": "^2.12.0",
|
||||
"i18next": "^19.8.7",
|
||||
"lodash": "^4.17.20",
|
||||
"nanoevents": "^5.1.11",
|
||||
"postcss": "^8.2.6",
|
||||
"react": "^17.0.1",
|
||||
"react-beautiful-dnd": "^13.0.0",
|
||||
"react-dom": "^17.0.1",
|
||||
"gatsby-plugin-image": "^1.6.0",
|
||||
"gatsby-plugin-manifest": "^3.6.0",
|
||||
"gatsby-plugin-material-ui": "^3.0.1",
|
||||
"gatsby-plugin-offline": "^4.6.0",
|
||||
"gatsby-plugin-postcss": "^4.6.0",
|
||||
"gatsby-plugin-react-helmet": "^4.6.0",
|
||||
"gatsby-plugin-sharp": "^3.6.0",
|
||||
"gatsby-plugin-sitemap": "^4.2.0",
|
||||
"gatsby-plugin-webfonts": "^2.1.0",
|
||||
"gatsby-source-filesystem": "^3.6.0",
|
||||
"gatsby-source-gravatar": "^1.0.1",
|
||||
"gatsby-transformer-remark": "^4.3.0",
|
||||
"gatsby-transformer-sharp": "^3.6.0",
|
||||
"i18next": "^20.3.1",
|
||||
"lodash": "^4.17.21",
|
||||
"nanoevents": "^6.0.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"postcss": "^8.3.0",
|
||||
"process": "^0.11.10",
|
||||
"react": "^17.0.2",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-i18next": "^11.8.6",
|
||||
"react-i18next": "^11.10.0",
|
||||
"react-icons": "^4.2.0",
|
||||
"react-markdown": "^5.0.3",
|
||||
"react-scroll": "^1.8.1",
|
||||
"react-toastify": "^7.0.3",
|
||||
"short-unique-id": "^3.2.3",
|
||||
"react-markdown": "^6.0.2",
|
||||
"react-scroll": "^1.8.2",
|
||||
"react-toastify": "^7.0.4",
|
||||
"short-unique-id": "^4.3.3",
|
||||
"uuid": "^8.3.2",
|
||||
"yup": "^0.32.8"
|
||||
"yup": "^0.32.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.11.9",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"babel-jest": "^26.6.3",
|
||||
"babel-preset-gatsby": "^0.12.1",
|
||||
"eslint": "^7.20.0",
|
||||
"@testing-library/jest-dom": "^5.12.0",
|
||||
"@testing-library/react": "^11.2.7",
|
||||
"babel-jest": "^27.0.1",
|
||||
"babel-preset-gatsby": "^1.6.0",
|
||||
"eslint": "^7.27.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-prettier": "^7.2.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-jest": "^24.1.3",
|
||||
"eslint-plugin-jest": "^24.3.6",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-react": "^7.22.0",
|
||||
"eslint-webpack-plugin": "^2.5.1",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"eslint-plugin-sort-imports-es6-autofix": "^0.6.0",
|
||||
"eslint-webpack-plugin": "^2.5.4",
|
||||
"gatsby-plugin-eslint": "^3.0.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest": "^27.0.1",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"prettier": "2.2.1",
|
||||
"stylelint": "^13.10.0",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"tailwindcss": "^2.0.3"
|
||||
"prettier": "2.3.0",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"tailwindcss": "^2.1.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react/no-danger */
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { graphql } from 'gatsby';
|
||||
import React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import styles from './Blog.module.css';
|
||||
import Wrapper from './shared/Wrapper';
|
||||
import Hero from './landing/Hero';
|
||||
import * as styles from './Blog.module.css';
|
||||
import Wrapper from './shared/Wrapper';
|
||||
|
||||
export default function Template({ data }) {
|
||||
const { markdownRemark } = data;
|
||||
@@ -34,7 +34,7 @@ export default function Template({ data }) {
|
||||
}
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query($slug: String!) {
|
||||
query ($slug: String!) {
|
||||
markdownRemark(frontmatter: { slug: { eq: $slug } }) {
|
||||
html
|
||||
frontmatter {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { memo } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import * as styles from './Artboard.module.css';
|
||||
import { useSelector } from '../../../contexts/ResumeContext';
|
||||
import Castform from '../../../templates/Castform';
|
||||
import Celebi from '../../../templates/Celebi';
|
||||
@@ -8,7 +9,6 @@ import Gengar from '../../../templates/Gengar';
|
||||
import Glalie from '../../../templates/Glalie';
|
||||
import Onyx from '../../../templates/Onyx';
|
||||
import Pikachu from '../../../templates/Pikachu';
|
||||
import styles from './Artboard.module.css';
|
||||
|
||||
const Artboard = () => {
|
||||
const state = useSelector();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Link } from 'gatsby';
|
||||
import React, { memo } from 'react';
|
||||
import { Tooltip } from '@material-ui/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import sections from '../../../data/leftSections';
|
||||
import React, { memo } from 'react';
|
||||
import Avatar from '../../shared/Avatar';
|
||||
import Logo from '../../shared/Logo';
|
||||
import * as styles from './LeftNavbar.module.css';
|
||||
import SectionIcon from '../../shared/SectionIcon';
|
||||
import styles from './LeftNavbar.module.css';
|
||||
import sections from '../../../data/leftSections';
|
||||
|
||||
const LeftNavbar = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import React, { Fragment, memo } from 'react';
|
||||
import { Element } from 'react-scroll';
|
||||
import sections from '../../../data/leftSections';
|
||||
import LeftNavbar from './LeftNavbar';
|
||||
import styles from './LeftSidebar.module.css';
|
||||
import React, { Fragment, memo } from 'react';
|
||||
import * as styles from './LeftSidebar.module.css';
|
||||
import Awards from './sections/Awards';
|
||||
import Certifications from './sections/Certifications';
|
||||
import Education from './sections/Education';
|
||||
import Hobbies from './sections/Hobbies';
|
||||
import Languages from './sections/Languages';
|
||||
import LeftNavbar from './LeftNavbar';
|
||||
import Objective from './sections/Objective';
|
||||
import Profile from './sections/Profile';
|
||||
import Projects from './sections/Projects';
|
||||
@@ -15,6 +14,7 @@ import References from './sections/References';
|
||||
import Skills from './sections/Skills';
|
||||
import Social from './sections/Social';
|
||||
import Work from './sections/Work';
|
||||
import sections from '../../../data/leftSections';
|
||||
|
||||
const getComponent = (id) => {
|
||||
switch (id) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import PhotoUpload from '../../../shared/PhotoUpload';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import List from '../../lists/List';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
|
||||
const EmptyList = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { get, isEmpty } from 'lodash';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdAdd } from 'react-icons/md';
|
||||
import ModalContext from '../../../contexts/ModalContext';
|
||||
import { useDispatch, useSelector } from '../../../contexts/ResumeContext';
|
||||
import { get, isEmpty } from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import * as styles from './List.module.css';
|
||||
import { formatDateRange, reorder } from '../../../utils';
|
||||
import { useDispatch, useSelector } from '../../../contexts/ResumeContext';
|
||||
import Button from '../../shared/Button';
|
||||
import EmptyList from './EmptyList';
|
||||
import styles from './List.module.css';
|
||||
import ListItem from './ListItem';
|
||||
import ModalContext from '../../../contexts/ModalContext';
|
||||
|
||||
const List = ({
|
||||
path,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Menu, MenuItem } from '@material-ui/core';
|
||||
import React, { memo, useState } from 'react';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
|
||||
import { MdMoreVert } from 'react-icons/md';
|
||||
import { Menu, MenuItem } from '@material-ui/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo, useState } from 'react';
|
||||
import Switch from '@material-ui/core/Switch';
|
||||
import { useDispatch } from '../../../contexts/ResumeContext';
|
||||
import styles from './ListItem.module.css';
|
||||
import * as styles from './ListItem.module.css';
|
||||
|
||||
const dataTestIdPrefix = 'list-item-';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { memo } from 'react';
|
||||
import sections from '../../../data/rightSections';
|
||||
import * as styles from './RightNavbar.module.css';
|
||||
import SectionIcon from '../../shared/SectionIcon';
|
||||
import styles from './RightNavbar.module.css';
|
||||
import SyncIndicator from './SyncIndicator';
|
||||
import sections from '../../../data/rightSections';
|
||||
|
||||
const RightNavbar = () => (
|
||||
<div className={styles.container}>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React, { Fragment, memo } from 'react';
|
||||
import { Element } from 'react-scroll';
|
||||
import sections from '../../../data/rightSections';
|
||||
import RightNavbar from './RightNavbar';
|
||||
import styles from './RightSidebar.module.css';
|
||||
import React, { Fragment, memo } from 'react';
|
||||
import * as styles from './RightSidebar.module.css';
|
||||
import About from './sections/About';
|
||||
import Actions from './sections/Actions';
|
||||
import Colors from './sections/Colors';
|
||||
import FontSize from './sections/FontSize';
|
||||
import Fonts from './sections/Fonts';
|
||||
import Layout from './sections/Layout';
|
||||
import RightNavbar from './RightNavbar';
|
||||
import Settings from './sections/Settings';
|
||||
import Templates from './sections/Templates';
|
||||
import FontSize from './sections/FontSize';
|
||||
import sections from '../../../data/rightSections';
|
||||
|
||||
const getComponent = (id) => {
|
||||
switch (id) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cx from 'classnames';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { MdSync } from 'react-icons/md';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import cx from 'classnames';
|
||||
import DatabaseContext from '../../../contexts/DatabaseContext';
|
||||
|
||||
const SyncIndicator = () => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { memo } from 'react';
|
||||
import { FaCoffee, FaBug, FaExternalLinkAlt } from 'react-icons/fa';
|
||||
import { FaBug, FaCoffee, FaExternalLinkAlt } from 'react-icons/fa';
|
||||
import { MdCode } from 'react-icons/md';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useStaticQuery, graphql } from 'gatsby';
|
||||
import { graphql, useStaticQuery } from 'gatsby';
|
||||
import React, { memo } from 'react';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './About.module.css';
|
||||
import * as styles from './About.module.css';
|
||||
|
||||
const About = ({ id }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { memo, useContext, useState } from 'react';
|
||||
import { FaFileExport, FaFileImport } from 'react-icons/fa';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ModalContext from '../../../../contexts/ModalContext';
|
||||
import React, { memo, useContext, useState } from 'react';
|
||||
import * as styles from './Actions.module.css';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import styles from './Actions.module.css';
|
||||
import ModalContext from '../../../../contexts/ModalContext';
|
||||
|
||||
const Actions = ({ id }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch } from '../../../../contexts/ResumeContext';
|
||||
import colorOptions from '../../../../data/colorOptions';
|
||||
import React, { memo } from 'react';
|
||||
import * as styles from './Colors.module.css';
|
||||
import { handleKeyUp } from '../../../../utils';
|
||||
import { useDispatch } from '../../../../contexts/ResumeContext';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import styles from './Colors.module.css';
|
||||
import colorOptions from '../../../../data/colorOptions';
|
||||
|
||||
const Colors = ({ id }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import fontSizeOptions from '../../../../data/fontSizeOptions';
|
||||
import { scaler } from '../../../../utils';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import fontSizeOptions from '../../../../data/fontSizeOptions';
|
||||
|
||||
const FontSizes = ({ id }) => {
|
||||
const steps = 20;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import cx from 'classnames';
|
||||
import React, { memo } from 'react';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import fontOptions from '../../../../data/fontOptions';
|
||||
import cx from 'classnames';
|
||||
import * as styles from './Fonts.module.css';
|
||||
import { handleKeyUp } from '../../../../utils';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Fonts.module.css';
|
||||
import fontOptions from '../../../../data/fontOptions';
|
||||
|
||||
const Fonts = ({ id }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { memo, useState } from 'react';
|
||||
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import React, { memo, useState } from 'react';
|
||||
import * as styles from './Layout.module.css';
|
||||
import { move, reorder } from '../../../../utils';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Layout.module.css';
|
||||
|
||||
const Layout = ({ id }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React, { memo, useContext, useState } from 'react';
|
||||
import { FaAngleDown } from 'react-icons/fa';
|
||||
import { useTranslation, Trans } from 'react-i18next';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { toast } from 'react-toastify';
|
||||
import UserContext from '../../../../contexts/UserContext';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Settings.module.css';
|
||||
import Input from '../../../shared/Input';
|
||||
import SettingsContext from '../../../../contexts/SettingsContext';
|
||||
import themeConfig from '../../../../data/themeConfig';
|
||||
import React, { memo, useContext, useState } from 'react';
|
||||
import * as styles from './Settings.module.css';
|
||||
import { languages } from '../../../../i18n';
|
||||
import { useDispatch } from '../../../../contexts/ResumeContext';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import SettingsContext from '../../../../contexts/SettingsContext';
|
||||
import UserContext from '../../../../contexts/UserContext';
|
||||
import themeConfig from '../../../../data/themeConfig';
|
||||
|
||||
const Settings = ({ id }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -18,15 +18,13 @@ const Settings = ({ id }) => {
|
||||
const [deleteText, setDeleteText] = useState(
|
||||
t('builder.settings.dangerZone.button'),
|
||||
);
|
||||
const [isDeleteAccountInProgress, setDeleteAccountInProgress] = useState(
|
||||
false,
|
||||
);
|
||||
const [isDeleteAccountInProgress, setDeleteAccountInProgress] =
|
||||
useState(false);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { deleteAccount } = useContext(UserContext);
|
||||
const { theme, setTheme, language, setLanguage } = useContext(
|
||||
SettingsContext,
|
||||
);
|
||||
const { theme, setTheme, language, setLanguage } =
|
||||
useContext(SettingsContext);
|
||||
|
||||
const handleChangeTheme = (e) => {
|
||||
setTheme(e.target.value);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import cx from 'classnames';
|
||||
import { graphql, useStaticQuery } from 'gatsby';
|
||||
import GatsbyImage from 'gatsby-image';
|
||||
import { GatsbyImage } from 'gatsby-plugin-image';
|
||||
import React, { memo } from 'react';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import templateOptions from '../../../../data/templateOptions';
|
||||
import cx from 'classnames';
|
||||
import * as styles from './Templates.module.css';
|
||||
import { handleKeyUp } from '../../../../utils';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Templates.module.css';
|
||||
import templateOptions from '../../../../data/templateOptions';
|
||||
|
||||
const Templates = ({ id }) => {
|
||||
const dispatch = useDispatch();
|
||||
@@ -16,44 +16,32 @@ const Templates = ({ id }) => {
|
||||
query {
|
||||
onyx: file(relativePath: { eq: "templates/onyx.png" }) {
|
||||
childImageSharp {
|
||||
fluid(maxHeight: 400) {
|
||||
...GatsbyImageSharpFluid
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, height: 240)
|
||||
}
|
||||
}
|
||||
pikachu: file(relativePath: { eq: "templates/pikachu.png" }) {
|
||||
childImageSharp {
|
||||
fluid(maxHeight: 400) {
|
||||
...GatsbyImageSharpFluid
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, height: 240)
|
||||
}
|
||||
}
|
||||
gengar: file(relativePath: { eq: "templates/gengar.png" }) {
|
||||
childImageSharp {
|
||||
fluid(maxHeight: 400) {
|
||||
...GatsbyImageSharpFluid
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, height: 240)
|
||||
}
|
||||
}
|
||||
castform: file(relativePath: { eq: "templates/castform.png" }) {
|
||||
childImageSharp {
|
||||
fluid(maxHeight: 400) {
|
||||
...GatsbyImageSharpFluid
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, height: 240)
|
||||
}
|
||||
}
|
||||
glalie: file(relativePath: { eq: "templates/glalie.png" }) {
|
||||
childImageSharp {
|
||||
fluid(maxHeight: 400) {
|
||||
...GatsbyImageSharpFluid
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, height: 240)
|
||||
}
|
||||
}
|
||||
celebi: file(relativePath: { eq: "templates/celebi.png" }) {
|
||||
childImageSharp {
|
||||
fluid(maxHeight: 400) {
|
||||
...GatsbyImageSharpFluid
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, height: 240)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,10 +75,7 @@ const Templates = ({ id }) => {
|
||||
>
|
||||
<GatsbyImage
|
||||
alt={x.name}
|
||||
loading="eager"
|
||||
className="w-full"
|
||||
style={{ height: '230px' }}
|
||||
fluid={previews[x.id].childImageSharp.fluid}
|
||||
image={previews[x.id].childImageSharp.gatsbyImageData}
|
||||
/>
|
||||
<span>{x.name}</span>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { MdAdd } from 'react-icons/md';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import * as styles from './CreateResume.module.css';
|
||||
import { handleKeyUp } from '../../utils';
|
||||
import styles from './CreateResume.module.css';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
|
||||
const createResumeButtonDataTestId = 'create-resume-button';
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { MdMoreHoriz, MdOpenInNew } from 'react-icons/md';
|
||||
import { Menu, MenuItem } from '@material-ui/core';
|
||||
import { navigate } from 'gatsby';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdMoreHoriz, MdOpenInNew } from 'react-icons/md';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import DatabaseContext from '../../contexts/DatabaseContext';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
import styles from './ResumePreview.module.css';
|
||||
import * as styles from './ResumePreview.module.css';
|
||||
|
||||
const menuToggleDataTestIdPrefix = 'resume-preview-menu-toggle-';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Link } from 'gatsby';
|
||||
import React, { memo } from 'react';
|
||||
import * as styles from './TopNavbar.module.css';
|
||||
import Avatar from '../shared/Avatar';
|
||||
import Logo from '../shared/Logo';
|
||||
import styles from './TopNavbar.module.css';
|
||||
|
||||
const TopNavbar = () => (
|
||||
<div className={styles.navbar}>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Link } from '@reach/router';
|
||||
import { navigate } from 'gatsby';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
import UserContext from '../../contexts/UserContext';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import Button from '../shared/Button';
|
||||
import Logo from '../shared/Logo';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
import UserContext from '../../contexts/UserContext';
|
||||
|
||||
const Hero = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { graphql, useStaticQuery } from 'gatsby';
|
||||
import { GatsbyImage } from 'gatsby-plugin-image';
|
||||
import React from 'react';
|
||||
import { useStaticQuery, graphql } from 'gatsby';
|
||||
import GatsbyImage from 'gatsby-image';
|
||||
import styles from './Screenshots.module.css';
|
||||
import * as styles from './Screenshots.module.css';
|
||||
|
||||
const Screenshots = () => {
|
||||
const screenshots = useStaticQuery(graphql`
|
||||
@@ -11,9 +11,7 @@ const Screenshots = () => {
|
||||
original {
|
||||
src
|
||||
}
|
||||
fixed(width: 320) {
|
||||
...GatsbyImageSharpFixed
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, width: 400)
|
||||
}
|
||||
}
|
||||
screen2: file(relativePath: { eq: "screenshots/screen-2.png" }) {
|
||||
@@ -21,9 +19,7 @@ const Screenshots = () => {
|
||||
original {
|
||||
src
|
||||
}
|
||||
fixed(width: 320) {
|
||||
...GatsbyImageSharpFixed
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, width: 400)
|
||||
}
|
||||
}
|
||||
screen3: file(relativePath: { eq: "screenshots/screen-3.png" }) {
|
||||
@@ -31,9 +27,7 @@ const Screenshots = () => {
|
||||
original {
|
||||
src
|
||||
}
|
||||
fixed(width: 320) {
|
||||
...GatsbyImageSharpFixed
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, width: 400)
|
||||
}
|
||||
}
|
||||
screen4: file(relativePath: { eq: "screenshots/screen-4.png" }) {
|
||||
@@ -41,9 +35,7 @@ const Screenshots = () => {
|
||||
original {
|
||||
src
|
||||
}
|
||||
fixed(width: 320) {
|
||||
...GatsbyImageSharpFixed
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, width: 400)
|
||||
}
|
||||
}
|
||||
screen5: file(relativePath: { eq: "screenshots/screen-5.png" }) {
|
||||
@@ -51,9 +43,7 @@ const Screenshots = () => {
|
||||
original {
|
||||
src
|
||||
}
|
||||
fixed(width: 320) {
|
||||
...GatsbyImageSharpFixed
|
||||
}
|
||||
gatsbyImageData(layout: FIXED, width: 400)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +64,7 @@ const Screenshots = () => {
|
||||
>
|
||||
<span className="sr-only">Reactive Resume Screenshot</span>
|
||||
<GatsbyImage
|
||||
fixed={screenshots[x].childImageSharp.fixed}
|
||||
image={screenshots[x].childImageSharp.gatsbyImageData}
|
||||
alt="Reactive Resume Screenshot"
|
||||
/>
|
||||
</a>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { navigate } from 'gatsby';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import UserContext from '../../contexts/UserContext';
|
||||
import LoadingScreen from './LoadingScreen';
|
||||
import UserContext from '../../contexts/UserContext';
|
||||
|
||||
const PrivateRoute = ({ component: Component, ...props }) => {
|
||||
const { user, loading } = useContext(UserContext);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import cx from 'classnames';
|
||||
import { toUrl } from 'gatsby-source-gravatar';
|
||||
import React, { memo, useContext, useMemo, useState } from 'react';
|
||||
import { Menu, MenuItem } from '@material-ui/core';
|
||||
import { toUrl } from 'gatsby-source-gravatar';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo, useContext, useMemo, useState } from 'react';
|
||||
import cx from 'classnames';
|
||||
import UserContext from '../../contexts/UserContext';
|
||||
import styles from './Avatar.module.css';
|
||||
import { handleKeyUp } from '../../utils';
|
||||
import * as styles from './Avatar.module.css';
|
||||
|
||||
const Avatar = ({ className }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -20,9 +20,10 @@ const Avatar = ({ className }) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const photoURL = useMemo(() => toUrl(user.email || '', 'size=128&d=retro'), [
|
||||
user.email,
|
||||
]);
|
||||
const photoURL = useMemo(
|
||||
() => toUrl(user.email || '', 'size=128&d=retro'),
|
||||
[user.email],
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import cx from 'classnames';
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { handleKeyUp } from '../../utils';
|
||||
import styles from './Button.module.css';
|
||||
import * as styles from './Button.module.css';
|
||||
|
||||
const Button = ({
|
||||
icon,
|
||||
@@ -22,7 +22,7 @@ const Button = ({
|
||||
onClick={isLoading ? undefined : onClick}
|
||||
className={cx(styles.container, className, {
|
||||
[styles.outline]: outline,
|
||||
[styles.delete]: isDelete,
|
||||
[styles.remove]: isDelete,
|
||||
})}
|
||||
>
|
||||
{icon && <Icon size="14" className="mr-3" />}
|
||||
|
||||
@@ -31,14 +31,14 @@
|
||||
@apply outline-none;
|
||||
}
|
||||
|
||||
.container.delete {
|
||||
.container.remove {
|
||||
@apply bg-red-600 border-red-600 text-white;
|
||||
}
|
||||
|
||||
.container.delete:hover {
|
||||
.container.remove:hover {
|
||||
@apply bg-red-700 border-red-700;
|
||||
}
|
||||
|
||||
.container.delete:focus {
|
||||
.container.remove:focus {
|
||||
@apply outline-none;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import { useSelector } from '../../contexts/ResumeContext';
|
||||
|
||||
const Heading = ({ id }) => {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import cx from 'classnames';
|
||||
import { isFunction } from 'lodash';
|
||||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { FaAngleDown } from 'react-icons/fa';
|
||||
import { MdOpenInNew } from 'react-icons/md';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { isFunction } from 'lodash';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import React, { memo, useEffect, useState } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { useDispatch, useSelector } from '../../contexts/ResumeContext';
|
||||
import { handleKeyUp } from '../../utils';
|
||||
import styles from './Input.module.css';
|
||||
import * as styles from './Input.module.css';
|
||||
|
||||
const Input = ({
|
||||
name,
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import cx from 'classnames';
|
||||
import { graphql, useStaticQuery } from 'gatsby';
|
||||
import GatsbyImage from 'gatsby-image';
|
||||
import { GatsbyImage } from 'gatsby-plugin-image';
|
||||
import React, { memo } from 'react';
|
||||
import styles from './Logo.module.css';
|
||||
import cx from 'classnames';
|
||||
import * as styles from './Logo.module.css';
|
||||
|
||||
const Logo = ({ size = '256px', className }) => {
|
||||
const { file } = useStaticQuery(graphql`
|
||||
query {
|
||||
file(relativePath: { eq: "logo.png" }) {
|
||||
childImageSharp {
|
||||
fluid(maxWidth: 512) {
|
||||
...GatsbyImageSharpFluid
|
||||
}
|
||||
gatsbyImageData(layout: FIXED)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,9 +18,10 @@ const Logo = ({ size = '256px', className }) => {
|
||||
return (
|
||||
<GatsbyImage
|
||||
loading="eager"
|
||||
alt="Reactive Resume"
|
||||
className={cx(styles.logo, className)}
|
||||
style={{ width: size, height: size }}
|
||||
fluid={file.childImageSharp.fluid}
|
||||
image={file.childImageSharp.gatsbyImageData}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Tooltip } from '@material-ui/core';
|
||||
import React, { memo, useContext, useRef } from 'react';
|
||||
import { MdFileUpload } from 'react-icons/md';
|
||||
import { Tooltip } from '@material-ui/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import StorageContext from '../../contexts/StorageContext';
|
||||
import React, { memo, useContext, useRef } from 'react';
|
||||
import { handleKeyUp } from '../../utils';
|
||||
import Input from './Input';
|
||||
import styles from './PhotoUpload.module.css';
|
||||
import * as styles from './PhotoUpload.module.css';
|
||||
import StorageContext from '../../contexts/StorageContext';
|
||||
|
||||
const PhotoUpload = () => {
|
||||
const fileInputRef = useRef(null);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Tooltip } from '@material-ui/core';
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-scroll';
|
||||
import styles from './SectionIcon.module.css';
|
||||
import { Tooltip } from '@material-ui/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import * as styles from './SectionIcon.module.css';
|
||||
|
||||
const SectionIcon = ({ section, containerId, tooltipPlacement }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { memo, useEffect } from 'react';
|
||||
import { Slide, toast } from 'react-toastify';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Slide, toast } from 'react-toastify';
|
||||
import React, { memo, useEffect } from 'react';
|
||||
import ModalRegistrar from '../../modals/ModalRegistrar';
|
||||
|
||||
const Wrapper = ({ children }) => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import { debounce } from 'lodash';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import React, { createContext, memo, useContext, useState } from 'react';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import UserContext from './UserContext';
|
||||
import initialState from '../data/initialState.json';
|
||||
import { getUnsplashPhoto } from '../utils';
|
||||
import initialState from '../data/initialState.json';
|
||||
|
||||
const DEBOUNCE_WAIT_TIME = 4000;
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import arrayMove from 'array-move';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import {
|
||||
clone,
|
||||
findIndex,
|
||||
get,
|
||||
has,
|
||||
isUndefined,
|
||||
merge,
|
||||
setWith,
|
||||
set,
|
||||
has,
|
||||
setWith,
|
||||
} from 'lodash';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import React, {
|
||||
createContext,
|
||||
memo,
|
||||
@@ -17,10 +16,11 @@ import React, {
|
||||
useContext,
|
||||
useReducer,
|
||||
} from 'react';
|
||||
import arrayMove from 'array-move';
|
||||
import i18next from 'i18next';
|
||||
import demoState from '../data/demoState.json';
|
||||
import initialState from '../data/initialState.json';
|
||||
import DatabaseContext from './DatabaseContext';
|
||||
import initialState from '../data/initialState.json';
|
||||
|
||||
const ResumeContext = createContext({});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import i18next from 'i18next';
|
||||
import React, { createContext, memo, useEffect, useState } from 'react';
|
||||
import i18next from 'i18next';
|
||||
import themeConfig from '../data/themeConfig';
|
||||
|
||||
const languageStorageItemKey = 'language';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import React, { createContext, memo, useContext, useRef } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import React, { createContext, memo, useContext, useRef } from 'react';
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import { isFileImage } from '../utils';
|
||||
import { useDispatch, useSelector } from './ResumeContext';
|
||||
import UserContext from './UserContext';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { navigate } from '@reach/router';
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import { pick } from 'lodash';
|
||||
import React, { createContext, memo, useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import React, { createContext, memo, useEffect, useState } from 'react';
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import useAuthState from '../hooks/useAuthState';
|
||||
|
||||
const defaultUser = {
|
||||
@@ -66,8 +66,8 @@ const UserProvider = ({ children }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
firebase.auth().signOut();
|
||||
const logout = async () => {
|
||||
await firebase.auth().signOut();
|
||||
localStorage.removeItem('user');
|
||||
setUser(null);
|
||||
navigate('/');
|
||||
@@ -123,7 +123,7 @@ const UserProvider = ({ children }) => {
|
||||
} catch (error) {
|
||||
toast.error(error.message);
|
||||
} finally {
|
||||
logout();
|
||||
await logout();
|
||||
toast(
|
||||
"It's sad to see you go, but we respect your privacy. All your data has been deleted successfully. Hope to see you again soon!",
|
||||
);
|
||||
|
||||
@@ -2,11 +2,11 @@ import {
|
||||
MdColorLens,
|
||||
MdDashboard,
|
||||
MdFontDownload,
|
||||
MdFormatSize,
|
||||
MdImportExport,
|
||||
MdInfo,
|
||||
MdSettings,
|
||||
MdStyle,
|
||||
MdFormatSize,
|
||||
} from 'react-icons/md';
|
||||
|
||||
export default [
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import i18n from 'i18next';
|
||||
import resources from './locales';
|
||||
|
||||
const languages = [
|
||||
|
||||
@@ -14,8 +14,8 @@ import it from './it.json';
|
||||
import ja from './ja.json';
|
||||
import kn from './kn.json';
|
||||
import lt from './lt.json';
|
||||
import nl from './nl.json';
|
||||
import nb from './nb.json';
|
||||
import nl from './nl.json';
|
||||
import pl from './pl.json';
|
||||
import ptBr from './pt-br.json';
|
||||
import ptPt from './pt-pt.json';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { navigate } from 'gatsby';
|
||||
import React, { memo, useContext, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo, useContext, useEffect, useState } from 'react';
|
||||
import BaseModal from './BaseModal';
|
||||
import Button from '../components/shared/Button';
|
||||
import ModalContext from '../contexts/ModalContext';
|
||||
import UserContext from '../contexts/UserContext';
|
||||
import BaseModal from './BaseModal';
|
||||
|
||||
const AuthModal = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -13,9 +13,8 @@ const AuthModal = () => {
|
||||
const [isLoadingAnonymous, setLoadingAnonymous] = useState(false);
|
||||
|
||||
const { emitter, events } = useContext(ModalContext);
|
||||
const { user, loginWithGoogle, loginAnonymously, logout } = useContext(
|
||||
UserContext,
|
||||
);
|
||||
const { user, loginWithGoogle, loginAnonymously, logout } =
|
||||
useContext(UserContext);
|
||||
|
||||
useEffect(() => {
|
||||
const unbind = emitter.on(events.AUTH_MODAL, () => setOpen(true));
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Backdrop, Fade, Modal } from '@material-ui/core';
|
||||
import { isFunction } from 'lodash';
|
||||
import React, { forwardRef, memo, useImperativeHandle } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdClose } from 'react-icons/md';
|
||||
import { isFunction } from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { forwardRef, memo, useImperativeHandle } from 'react';
|
||||
import Button from '../components/shared/Button';
|
||||
import { handleKeyUp } from '../utils';
|
||||
import styles from './BaseModal.module.css';
|
||||
import * as styles from './BaseModal.module.css';
|
||||
|
||||
const BaseModal = forwardRef(
|
||||
({ title, state, children, action, hideActions = false, onDestroy }, ref) => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useFormikContext } from 'formik';
|
||||
import { isEmpty, isFunction } from 'lodash';
|
||||
import React, { memo, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import React, { memo, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { useDispatch } from '../contexts/ResumeContext';
|
||||
import BaseModal from './BaseModal';
|
||||
import Button from '../components/shared/Button';
|
||||
import ModalContext from '../contexts/ModalContext';
|
||||
import { useDispatch } from '../contexts/ResumeContext';
|
||||
import { getModalText } from '../utils';
|
||||
import BaseModal from './BaseModal';
|
||||
|
||||
const DataModal = ({
|
||||
name,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { memo } from 'react';
|
||||
import AuthModal from './AuthModal';
|
||||
import ResumeModal from './ResumeModal';
|
||||
import AwardModal from './sections/AwardModal';
|
||||
import CertificateModal from './sections/CertificateModal';
|
||||
import EducationModal from './sections/EducationModal';
|
||||
@@ -10,6 +9,7 @@ import ImportModal from './sections/ImportModal';
|
||||
import LanguageModal from './sections/LanguageModal';
|
||||
import ProjectModal from './sections/ProjectModal';
|
||||
import ReferenceModal from './sections/ReferenceModal';
|
||||
import ResumeModal from './ResumeModal';
|
||||
import SkillModal from './sections/SkillModal';
|
||||
import SocialModal from './sections/SocialModal';
|
||||
import WorkModal from './sections/WorkModal';
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Input from '../components/shared/Input';
|
||||
import ModalEvents from '../constants/ModalEvents';
|
||||
import DatabaseContext from '../contexts/DatabaseContext';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { getFieldProps } from '../utils';
|
||||
import DataModal from './DataModal';
|
||||
import DatabaseContext from '../contexts/DatabaseContext';
|
||||
import Input from '../components/shared/Input';
|
||||
import ModalEvents from '../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
name: '',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Yup from 'yup';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
title: '',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Yup from 'yup';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
title: '',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
institution: '',
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { FaPrint } from 'react-icons/fa';
|
||||
import { clone } from 'lodash';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo, useContext, useEffect, useState } from 'react';
|
||||
import download from 'downloadjs';
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import { clone } from 'lodash';
|
||||
import React, { memo, useContext, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaPrint } from 'react-icons/fa';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useSelector } from '../../contexts/ResumeContext';
|
||||
import BaseModal from '../BaseModal';
|
||||
import Button from '../../components/shared/Button';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
import { useSelector } from '../../contexts/ResumeContext';
|
||||
import { b64toBlob } from '../../utils';
|
||||
import BaseModal from '../BaseModal';
|
||||
|
||||
const ExportModal = () => {
|
||||
const state = useSelector();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
name: '',
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Tooltip } from '@material-ui/core';
|
||||
import React, { memo, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Button from '../../components/shared/Button';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
import React, { memo, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { useDispatch } from '../../contexts/ResumeContext';
|
||||
import BaseModal from '../BaseModal';
|
||||
import Button from '../../components/shared/Button';
|
||||
import ModalContext from '../../contexts/ModalContext';
|
||||
|
||||
const ImportModal = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Yup from 'yup';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
name: '',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
title: '',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
name: '',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Formik } from 'formik';
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Yup from 'yup';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
import { Formik } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { memo } from 'react';
|
||||
import { getFieldProps } from '../../utils';
|
||||
import DataModal from '../DataModal';
|
||||
import Input from '../../components/shared/Input';
|
||||
import ModalEvents from '../../constants/ModalEvents';
|
||||
|
||||
const initialValues = {
|
||||
name: '',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user