mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-19 03:01:53 +10:00
- memoize all components
- implement metadata context
This commit is contained in:
@ -1,8 +1,16 @@
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
memo,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import UserContext from './UserContext';
|
||||
|
||||
const DEBOUNCE_WAIT_TIME = 4000;
|
||||
|
||||
const defaultState = {
|
||||
isOffline: false,
|
||||
isUpdating: false,
|
||||
@ -10,7 +18,8 @@ const defaultState = {
|
||||
getResumes: async () => {},
|
||||
createResume: () => {},
|
||||
updateResume: async () => {},
|
||||
debouncedUpdate: async () => {},
|
||||
debouncedUpdateResume: async () => {},
|
||||
debouncedUpdateMetadata: async () => {},
|
||||
deleteResume: () => {},
|
||||
};
|
||||
|
||||
@ -77,7 +86,23 @@ const DatabaseProvider = ({ children }) => {
|
||||
setUpdating(false);
|
||||
};
|
||||
|
||||
const debouncedUpdate = debounce(updateResume, 2000);
|
||||
const debouncedUpdateResume = debounce(updateResume, DEBOUNCE_WAIT_TIME);
|
||||
|
||||
const updateMetadata = async (resumeId, metadata) => {
|
||||
setUpdating(true);
|
||||
|
||||
await firebase
|
||||
.database()
|
||||
.ref(`users/${user.uid}/resumes/${resumeId}`)
|
||||
.update({
|
||||
metadata,
|
||||
updatedAt: firebase.database.ServerValue.TIMESTAMP,
|
||||
});
|
||||
|
||||
setUpdating(false);
|
||||
};
|
||||
|
||||
const debouncedUpdateMetadata = debounce(updateMetadata, DEBOUNCE_WAIT_TIME);
|
||||
|
||||
const deleteResume = (id) => {
|
||||
firebase.database().ref(`users/${user.uid}/resumes/${id}`).remove();
|
||||
@ -91,7 +116,8 @@ const DatabaseProvider = ({ children }) => {
|
||||
getResume,
|
||||
createResume,
|
||||
updateResume,
|
||||
debouncedUpdate,
|
||||
debouncedUpdateResume,
|
||||
debouncedUpdateMetadata,
|
||||
deleteResume,
|
||||
}}
|
||||
>
|
||||
@ -102,4 +128,6 @@ const DatabaseProvider = ({ children }) => {
|
||||
|
||||
export default DatabaseContext;
|
||||
|
||||
export { DatabaseProvider };
|
||||
const memoizedProvider = memo(DatabaseProvider);
|
||||
|
||||
export { memoizedProvider as DatabaseProvider };
|
||||
|
||||
70
src/contexts/MetadataContext.js
Normal file
70
src/contexts/MetadataContext.js
Normal file
@ -0,0 +1,70 @@
|
||||
import { clone, setWith } from 'lodash';
|
||||
import React, {
|
||||
createContext,
|
||||
memo,
|
||||
useCallback,
|
||||
useContext,
|
||||
useReducer,
|
||||
} from 'react';
|
||||
import leftSections from '../data/leftSections';
|
||||
import DatabaseContext from './DatabaseContext';
|
||||
import { useSelector as useResumeSelector } from './ResumeContext';
|
||||
|
||||
const initialState = {
|
||||
template: 'Onyx',
|
||||
font: 'Montserrat',
|
||||
layout: [leftSections.map(({ id, name }) => ({ id, name }))],
|
||||
colors: {
|
||||
textColor: '#444444',
|
||||
primaryColor: '#5875DB',
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
};
|
||||
|
||||
const MetadataContext = createContext({});
|
||||
|
||||
const MetadataProvider = ({ children }) => {
|
||||
const id = useResumeSelector((state) => state.id);
|
||||
const { debouncedUpdateMetadata } = useContext(DatabaseContext);
|
||||
|
||||
const memoizedReducer = useCallback(
|
||||
(state, { type, payload }) => {
|
||||
let newState;
|
||||
|
||||
switch (type) {
|
||||
case 'set_layout':
|
||||
newState = setWith(clone(state), 'layout', payload, clone);
|
||||
debouncedUpdateMetadata(id, newState);
|
||||
return newState;
|
||||
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
[id, debouncedUpdateMetadata],
|
||||
);
|
||||
|
||||
const [state, dispatch] = useReducer(memoizedReducer, initialState);
|
||||
|
||||
const selectValue = (callback) => callback(state);
|
||||
|
||||
return (
|
||||
<MetadataContext.Provider value={{ selectValue, dispatch }}>
|
||||
{children}
|
||||
</MetadataContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const useSelector = (callback) => {
|
||||
const { selectValue } = useContext(MetadataContext);
|
||||
return selectValue(callback);
|
||||
};
|
||||
|
||||
const useDispatch = () => {
|
||||
const { dispatch } = useContext(MetadataContext);
|
||||
return dispatch;
|
||||
};
|
||||
|
||||
const memoizedProvider = memo(MetadataProvider);
|
||||
|
||||
export { memoizedProvider as MetadataProvider, useSelector, useDispatch };
|
||||
@ -1,5 +1,5 @@
|
||||
import { createNanoEvents } from 'nanoevents';
|
||||
import React, { createContext } from 'react';
|
||||
import React, { createContext, memo } from 'react';
|
||||
import ModalEvents from '../constants/ModalEvents';
|
||||
|
||||
const emitter = createNanoEvents();
|
||||
@ -18,4 +18,6 @@ const ModalProvider = ({ children }) => {
|
||||
|
||||
export default ModalContext;
|
||||
|
||||
export { ModalProvider };
|
||||
const memoizedProvider = memo(ModalProvider);
|
||||
|
||||
export { memoizedProvider as ModalProvider };
|
||||
|
||||
@ -2,6 +2,7 @@ import arrayMove from 'array-move';
|
||||
import { clone, findIndex, get, setWith } from 'lodash';
|
||||
import React, {
|
||||
createContext,
|
||||
memo,
|
||||
useCallback,
|
||||
useContext,
|
||||
useReducer,
|
||||
@ -10,10 +11,10 @@ import DatabaseContext from './DatabaseContext';
|
||||
|
||||
const initialState = {};
|
||||
|
||||
const ResumeContext = createContext(initialState);
|
||||
const ResumeContext = createContext({});
|
||||
|
||||
const ResumeProvider = ({ children }) => {
|
||||
const { debouncedUpdate } = useContext(DatabaseContext);
|
||||
const { debouncedUpdateResume } = useContext(DatabaseContext);
|
||||
|
||||
const memoizedReducer = useCallback(
|
||||
(state, { type, payload }) => {
|
||||
@ -31,7 +32,7 @@ const ResumeProvider = ({ children }) => {
|
||||
[...items, payload.value],
|
||||
clone,
|
||||
);
|
||||
debouncedUpdate(newState);
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'on_edit_item':
|
||||
@ -44,7 +45,7 @@ const ResumeProvider = ({ children }) => {
|
||||
payload.value,
|
||||
clone,
|
||||
);
|
||||
debouncedUpdate(newState);
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'on_delete_item':
|
||||
@ -52,7 +53,7 @@ const ResumeProvider = ({ children }) => {
|
||||
index = findIndex(items, ['id', payload.value.id]);
|
||||
items.splice(index, 1);
|
||||
newState = setWith(clone(state), payload.path, items, clone);
|
||||
debouncedUpdate(newState);
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'on_move_item_up':
|
||||
@ -60,7 +61,7 @@ const ResumeProvider = ({ children }) => {
|
||||
index = findIndex(items, ['id', payload.value.id]);
|
||||
items = arrayMove(items, index, index - 1);
|
||||
newState = setWith(clone(state), payload.path, items, clone);
|
||||
debouncedUpdate(newState);
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'on_move_item_down':
|
||||
@ -68,12 +69,12 @@ const ResumeProvider = ({ children }) => {
|
||||
index = findIndex(items, ['id', payload.value.id]);
|
||||
items = arrayMove(items, index, index + 1);
|
||||
newState = setWith(clone(state), payload.path, items, clone);
|
||||
debouncedUpdate(newState);
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'on_input':
|
||||
newState = setWith(clone(state), payload.path, payload.value, clone);
|
||||
debouncedUpdate(newState);
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'set_data':
|
||||
@ -83,7 +84,7 @@ const ResumeProvider = ({ children }) => {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
[debouncedUpdate],
|
||||
[debouncedUpdateResume],
|
||||
);
|
||||
|
||||
const [state, dispatch] = useReducer(memoizedReducer, initialState);
|
||||
@ -107,4 +108,6 @@ const useDispatch = () => {
|
||||
return dispatch;
|
||||
};
|
||||
|
||||
export { ResumeProvider, useSelector, useDispatch };
|
||||
const memoizedProvider = memo(ResumeProvider);
|
||||
|
||||
export { memoizedProvider as ResumeProvider, useSelector, useDispatch };
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import React, { createContext, useContext, useRef } from 'react';
|
||||
import React, { createContext, memo, useContext, useRef } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { isFileImage } from '../utils';
|
||||
import { useDispatch, useSelector } from './ResumeContext';
|
||||
@ -84,4 +84,6 @@ const StorageProvider = ({ children }) => {
|
||||
|
||||
export default StorageContext;
|
||||
|
||||
export { StorageProvider };
|
||||
const memoizedProvider = memo(StorageProvider);
|
||||
|
||||
export { memoizedProvider as StorageProvider };
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
import { flatten } from 'lodash';
|
||||
import React, { createContext, useState } from 'react';
|
||||
import leftSections from '../data/leftSections';
|
||||
|
||||
const defaultState = {
|
||||
selected: 'Onyx',
|
||||
setSelected: () => {},
|
||||
colors: {
|
||||
textColor: '#212121',
|
||||
primaryColor: '#f44336',
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
blocks: [leftSections],
|
||||
setBlocks: () => {},
|
||||
setFixedBlocks: () => {},
|
||||
setSupportedBlocks: () => {},
|
||||
};
|
||||
|
||||
const TemplateContext = createContext(defaultState);
|
||||
|
||||
const TemplateProvider = ({ children }) => {
|
||||
const [selected, setSelected] = useState(defaultState.selected);
|
||||
const [colors, setColors] = useState(defaultState.colors);
|
||||
const [blocks, setBlocks] = useState(defaultState.blocks);
|
||||
|
||||
const reorder = (list, startIndex, endIndex) => {
|
||||
const result = Array.from(list);
|
||||
const [removed] = result.splice(startIndex, 1);
|
||||
result.splice(endIndex, 0, removed);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const move = (source, destination, droppableSource, droppableDestination) => {
|
||||
const sourceClone = Array.from(source);
|
||||
const destClone = Array.from(destination);
|
||||
const [removed] = sourceClone.splice(droppableSource.index, 1);
|
||||
|
||||
destClone.splice(droppableDestination.index, 0, removed);
|
||||
|
||||
const result = {};
|
||||
result[droppableSource.droppableId] = sourceClone;
|
||||
result[droppableDestination.droppableId] = destClone;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const onDragEnd = (result) => {
|
||||
const { source, destination } = result;
|
||||
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
const sInd = +source.droppableId;
|
||||
const dInd = +destination.droppableId;
|
||||
|
||||
if (sInd === dInd) {
|
||||
const items = reorder(blocks[sInd], source.index, destination.index);
|
||||
const newState = [...blocks];
|
||||
newState[sInd] = items;
|
||||
setBlocks(newState);
|
||||
} else {
|
||||
const newResult = move(blocks[sInd], blocks[dInd], source, destination);
|
||||
const newState = [...blocks];
|
||||
newState[sInd] = newResult[sInd];
|
||||
newState[dInd] = newResult[dInd];
|
||||
setBlocks(newState);
|
||||
}
|
||||
};
|
||||
|
||||
const setFixedBlocks = (fixedBlocks) => {
|
||||
const newBlocks = blocks.map((x) =>
|
||||
x.filter((y) => !fixedBlocks.includes(y)),
|
||||
);
|
||||
setBlocks(newBlocks);
|
||||
};
|
||||
|
||||
const setSupportedBlocks = (number) => {
|
||||
if (number === blocks.length) return;
|
||||
|
||||
if (number > blocks.length) {
|
||||
setBlocks([...blocks, []]);
|
||||
}
|
||||
|
||||
if (number < blocks.length) {
|
||||
setBlocks([flatten(blocks)]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TemplateContext.Provider
|
||||
value={{
|
||||
colors,
|
||||
blocks,
|
||||
selected,
|
||||
setColors,
|
||||
setBlocks,
|
||||
onDragEnd,
|
||||
setSelected,
|
||||
setFixedBlocks,
|
||||
setSupportedBlocks,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</TemplateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateContext;
|
||||
|
||||
export { TemplateProvider };
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { createContext, useEffect, useState } from 'react';
|
||||
import React, { createContext, memo, useEffect, useState } from 'react';
|
||||
|
||||
const COLOR_CONFIG = {
|
||||
light: {
|
||||
@ -62,4 +62,6 @@ const ThemeProvider = ({ children }) => {
|
||||
|
||||
export default ThemeContext;
|
||||
|
||||
export { ThemeProvider };
|
||||
const memoizedProvider = memo(ThemeProvider);
|
||||
|
||||
export { memoizedProvider as ThemeProvider };
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import { pick } from 'lodash';
|
||||
import React, { createContext, useEffect, useState } from 'react';
|
||||
import React, { createContext, memo, useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import useAuthState from '../hooks/useAuthState';
|
||||
|
||||
@ -77,4 +77,6 @@ const UserProvider = ({ children }) => {
|
||||
|
||||
export default UserContext;
|
||||
|
||||
export { UserProvider };
|
||||
const memoizedProvider = memo(UserProvider);
|
||||
|
||||
export { memoizedProvider as UserProvider };
|
||||
|
||||
Reference in New Issue
Block a user