diff --git a/.eslintrc b/.eslintrc index 68499025..4792df35 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,7 @@ { "globals": { "document": true, + "FileReader": true, "localStorage": true }, "extends": ["airbnb", "prettier"], diff --git a/package-lock.json b/package-lock.json index fa762c1f..cf1b33d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1089,14 +1089,14 @@ "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, "@firebase/analytics": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.3.8.tgz", - "integrity": "sha512-HpNRBJHnrGq5jtVTNRgA8Ozng2ilt0pkej8D5EvXoaylu80U+ICKLBlIT8TdUSEfkXC/RPjvLXg6vn/sq/CyqA==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.3.9.tgz", + "integrity": "sha512-l4dNskm8uQ+UqO6Lw+fuyO1enZBXUV6xNMxeVABEnVrp3wOP90KKb/ZwYgleAxF1It52lorcTtkA1YFpv3iEIQ==", "requires": { "@firebase/analytics-types": "0.3.1", - "@firebase/component": "0.1.15", - "@firebase/installations": "0.4.13", - "@firebase/logger": "0.2.5", + "@firebase/component": "0.1.16", + "@firebase/installations": "0.4.14", + "@firebase/logger": "0.2.6", "@firebase/util": "0.2.50", "tslib": "^1.11.1" } @@ -1107,13 +1107,13 @@ "integrity": "sha512-63vVJ5NIBh/JF8l9LuPrQYSzFimk7zYHySQB4Dk9rVdJ8kV/vGQoVTvRu1UW05sEc2Ug5PqtEChtTHU+9hvPcA==" }, "@firebase/app": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.6.7.tgz", - "integrity": "sha512-6NpIZ3iMrCR2XOShK5oi3YYB0GXX5yxVD8p3+2N+X4CF5cERyIrDRf8+YXOFgr+bDHSbVcIyzpWv6ijhg4MJlw==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.6.8.tgz", + "integrity": "sha512-Tm7Pi6Dtpx4FFKcpm0jcrZ/qI9oREBxmP3pWlw1jgDW4syRJHmN9/5DYvfFk6FAhj3FrY8E/6F+ngWJfqONotQ==", "requires": { "@firebase/app-types": "0.6.1", - "@firebase/component": "0.1.15", - "@firebase/logger": "0.2.5", + "@firebase/component": "0.1.16", + "@firebase/logger": "0.2.6", "@firebase/util": "0.2.50", "dom-storage": "2.1.0", "tslib": "^1.11.1", @@ -1126,9 +1126,9 @@ "integrity": "sha512-L/ZnJRAq7F++utfuoTKX4CLBG5YR7tFO3PLzG1/oXXKEezJ0kRL3CMRoueBEmTCzVb/6SIs2Qlaw++uDgi5Xyg==" }, "@firebase/auth": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.14.7.tgz", - "integrity": "sha512-NTQY9luV70XUA6zGYOWloDSaOT+l0/R4u3W7ptqVCfZNc4DAt7euUkTbj7SDD14902sHF54j+tk5kmpEmMd0jA==", + "version": "0.14.8", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.14.8.tgz", + "integrity": "sha512-LufoWcFpYAoCUkFDKSELH69xI8NdOjNTUFKvWfADZN7ysr4dpPdDs2ZYnH67FqcMb0tX+Jdx6vWrF6VZ37AAJQ==", "requires": { "@firebase/auth-types": "0.10.1" } @@ -1144,23 +1144,23 @@ "integrity": "sha512-/+gBHb1O9x/YlG7inXfxff/6X3BPZt4zgBv4kql6HEmdzNQCodIRlEYnI+/da+lN+dha7PjaFH7C7ewMmfV7rw==" }, "@firebase/component": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.15.tgz", - "integrity": "sha512-HqFb1qQl1vtlUMIzPM15plNz27jqM8DWjuQQuGeDfG+4iRRflwKfgNw1BOyoP4kQ8vOBCL7t/71yPXSomNdJdQ==", + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.16.tgz", + "integrity": "sha512-FvffvFN0LWgv1H/FIyruTECOL69Dhy+JfwoTq+mV39V8Mz9lNpo41etonL5AOr7KmXxYJVbNwkx0L9Ei88i7JA==", "requires": { "@firebase/util": "0.2.50", "tslib": "^1.11.1" } }, "@firebase/database": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.6.tgz", - "integrity": "sha512-TqUJOaCATF/h3wpqhPT9Fz1nZI6gBv/M2pHZztUjX4A9o9Bq93NyqUurYiZnGB7zpSkEADFCVT4f0VBrWdHlNw==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.7.tgz", + "integrity": "sha512-vm0ch2zNSoHfXWnDG6WVjf0p/BdXOMBL1lAfkGu3DYH/Rkl4p97x57w0WNOURNfL4GY2LIqScSYKCidV7jqTog==", "requires": { "@firebase/auth-interop-types": "0.1.5", - "@firebase/component": "0.1.15", + "@firebase/component": "0.1.16", "@firebase/database-types": "0.5.1", - "@firebase/logger": "0.2.5", + "@firebase/logger": "0.2.6", "@firebase/util": "0.2.50", "faye-websocket": "0.11.3", "tslib": "^1.11.1" @@ -1175,13 +1175,13 @@ } }, "@firebase/firestore": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.15.5.tgz", - "integrity": "sha512-unkRIC2hL2Ge5er/Hj43aUYiEKlW5bpju8TnIaF33avg/wZpSsmtVrMlAQVkBWFhvWeYpJSr2QOzNLa1bQvuCA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.16.0.tgz", + "integrity": "sha512-RsgGIP9e6HW5soEHIuo0CGVFpeTKe0hqjrgOLk92W0mjL6irzBlqmd5HcGMY4F5QiZryc2vMT1/3LvRhkUyf8g==", "requires": { - "@firebase/component": "0.1.15", - "@firebase/firestore-types": "1.11.0", - "@firebase/logger": "0.2.5", + "@firebase/component": "0.1.16", + "@firebase/firestore-types": "1.12.0", + "@firebase/logger": "0.2.6", "@firebase/util": "0.2.50", "@firebase/webchannel-wrapper": "0.2.41", "@grpc/grpc-js": "^1.0.0", @@ -1190,16 +1190,16 @@ } }, "@firebase/firestore-types": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-1.11.0.tgz", - "integrity": "sha512-hD7+cmMUvT5OJeWVrcRkE87PPuj/0/Wic6bntCopJE1WIX/Dm117AUkHgKd3S7Ici6DLp4bdlx1MjjwWL5942w==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-1.12.0.tgz", + "integrity": "sha512-OqNxVb63wPZdUc7YnpacAW1WNIMSKERSewCRi+unCQ0YI0KNfrDSypyGCyel+S3GdOtKMk9KnvDknaGbnaFX4g==" }, "@firebase/functions": { - "version": "0.4.47", - "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.47.tgz", - "integrity": "sha512-wiyMezW1EYq80Uk15M4poapCG10PjN5UJEY0jJr7DhCnDAoADMGlsIYFYio60+biGreij5/hpOybw5mU9WpXUw==", + "version": "0.4.48", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.48.tgz", + "integrity": "sha512-BwI/JzO/f/nquKG1IS3VqmwMaKEhvM58/08vTnp46krHBsOYqsdD9T2amz+HXGT9fe2HhDsUhgFE8D00S0vqbg==", "requires": { - "@firebase/component": "0.1.15", + "@firebase/component": "0.1.16", "@firebase/functions-types": "0.3.17", "@firebase/messaging-types": "0.4.5", "isomorphic-fetch": "2.2.1", @@ -1212,11 +1212,11 @@ "integrity": "sha512-DGR4i3VI55KnYk4IxrIw7+VG7Q3gA65azHnZxo98Il8IvYLr2UTBlSh72dTLlDf25NW51HqvJgYJDKvSaAeyHQ==" }, "@firebase/installations": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.4.13.tgz", - "integrity": "sha512-Sic7BtWgdUwk+Z1C4L49Edkhzaol/ijEIdv0pkHfjedIPirIU2V8CJ5qykx2y4aTiyVbdFqfjIpp1c6A6W3GBA==", + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.4.14.tgz", + "integrity": "sha512-hQPsaU7wdTq3CFMtFQwZy6LgdXZAkXoUToV4O+ekPbjM65QzaGVogJVU8O2H6ADXoq37SarcUXKe86pcUWdFLA==", "requires": { - "@firebase/component": "0.1.15", + "@firebase/component": "0.1.16", "@firebase/installations-types": "0.3.4", "@firebase/util": "0.2.50", "idb": "3.0.2", @@ -1229,17 +1229,17 @@ "integrity": "sha512-RfePJFovmdIXb6rYwtngyxuEcWnOrzdZd9m7xAW0gRxDIjBT20n3BOhjpmgRWXo/DAxRmS7bRjWAyTHY9cqN7Q==" }, "@firebase/logger": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.2.5.tgz", - "integrity": "sha512-qqw3m0tWs/qrg7axTZG/QZq24DIMdSY6dGoWuBn08ddq7+GLF5HiqkRj71XznYeUUbfRq5W9C/PSFnN4JxX+WA==" + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.2.6.tgz", + "integrity": "sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==" }, "@firebase/messaging": { - "version": "0.6.19", - "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.6.19.tgz", - "integrity": "sha512-PhqK69m70G+GGgvbdnGz2+PyoqfmR5b+nouj1JV+HgyBCjMAhF8rDYQzCWWgy4HaWbLoS/xW6AZUKG20Kv2H1A==", + "version": "0.6.20", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.6.20.tgz", + "integrity": "sha512-1MqyljXnbFBeHYhL6QInVM9aO5MW820yhNmOIVxk58wNXq4tOQLzqnKuvlgZ+ttgqlDzrIYiVf3EOHh5DptttQ==", "requires": { - "@firebase/component": "0.1.15", - "@firebase/installations": "0.4.13", + "@firebase/component": "0.1.16", + "@firebase/installations": "0.4.14", "@firebase/messaging-types": "0.4.5", "@firebase/util": "0.2.50", "idb": "3.0.2", @@ -1252,13 +1252,13 @@ "integrity": "sha512-sux4fgqr/0KyIxqzHlatI04Ajs5rc3WM+WmtCpxrKP1E5Bke8xu/0M+2oy4lK/sQ7nov9z15n3iltAHCgTRU3Q==" }, "@firebase/performance": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.3.8.tgz", - "integrity": "sha512-jODXrtFLyfnRiBehHuMBmsBtMv38U9sTictRxJSz+9JahvWYm1AF0YDzPlfeyYj+kxM6+S5wdQxUaPVdcWAvWg==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.3.9.tgz", + "integrity": "sha512-Fj22DZXRhhKv1OSUzDxX7AqpJUcDld6tzXK1yxOC8e3v1DFPQMQdM9FoG1m1b/Vrqa6pCCqnqG6gh6VPnEcAzQ==", "requires": { - "@firebase/component": "0.1.15", - "@firebase/installations": "0.4.13", - "@firebase/logger": "0.2.5", + "@firebase/component": "0.1.16", + "@firebase/installations": "0.4.14", + "@firebase/logger": "0.2.6", "@firebase/performance-types": "0.0.13", "@firebase/util": "0.2.50", "tslib": "^1.11.1" @@ -1287,13 +1287,13 @@ } }, "@firebase/remote-config": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.1.24.tgz", - "integrity": "sha512-/Kd+I5mNPI2wJJFySOC8Mjj4lRnEwZhU0RteuVlzFCDWWEyTE//r+p2TLAufQ9J+Fd3Ru5fVMFLNyU8k71Viiw==", + "version": "0.1.25", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.1.25.tgz", + "integrity": "sha512-8YWefBhy77HMbWXWdbenalx+IDY/XkS+iURQ9qRYvSIFYx6RL04DzlakZNOY9CQAcxTA+cTSt4NNlhjopBjf2Q==", "requires": { - "@firebase/component": "0.1.15", - "@firebase/installations": "0.4.13", - "@firebase/logger": "0.2.5", + "@firebase/component": "0.1.16", + "@firebase/installations": "0.4.14", + "@firebase/logger": "0.2.6", "@firebase/remote-config-types": "0.1.9", "@firebase/util": "0.2.50", "tslib": "^1.11.1" @@ -1305,11 +1305,11 @@ "integrity": "sha512-G96qnF3RYGbZsTRut7NBX0sxyczxt1uyCgXQuH/eAfUCngxjEGcZQnBdy6mvSdqdJh5mC31rWPO4v9/s7HwtzA==" }, "@firebase/storage": { - "version": "0.3.37", - "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.37.tgz", - "integrity": "sha512-RLbiRQlnvXRP/30OaEiUoRHBxZygqrZyotPPWD2WmD3JMM9qGTVpYNQ092mqL3R8ViyejwlpjlPvrDo7Z9BzgQ==", + "version": "0.3.38", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.38.tgz", + "integrity": "sha512-gWVQr5xqrU3cfhhwbAE+9iJ0XMvzbxWMvteKurn5cRNaGbmSob/O/ISOAvsQgPnk+K9zPMd2OwyzaTOl9PEMrw==", "requires": { - "@firebase/component": "0.1.15", + "@firebase/component": "0.1.16", "@firebase/storage-types": "0.3.12", "@firebase/util": "0.2.50", "tslib": "^1.11.1" @@ -1369,9 +1369,9 @@ } }, "@grpc/grpc-js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.1.tgz", - "integrity": "sha512-mhZRszS0SKwnWPJaNyrECePZ9U7vaHFGqrzxQbWinWR3WznBIU+nmh2L5J3elF+lp5DEUIzARXkifbs6LQVAHA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.2.tgz", + "integrity": "sha512-k2u86Bkm/3xrjUaSWeIyzXScBt/cC8uE7BznR0cpueQi11R33W6qfJdMrkrsmSHirp5likR55JSXUrcWG6ybHA==", "requires": { "semver": "^6.2.0" } @@ -8021,23 +8021,23 @@ } }, "firebase": { - "version": "7.15.5", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-7.15.5.tgz", - "integrity": "sha512-yeXo3KDp/ZWO0/Uyen99cUvGM76femebmyNOBTHcGSDkBXvIGth6235KhclxLROIKCC5b3YNwmKX11tbaC6RJg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-7.16.0.tgz", + "integrity": "sha512-fYimLYkY0SS/jv4+ZnSp5u2+QdtwsTtLwPUfmWiKQnjqas1M5mqhQr3QB7vPQuSANhC3UJZZ5KPxLbFomMJLcA==", "requires": { - "@firebase/analytics": "0.3.8", - "@firebase/app": "0.6.7", + "@firebase/analytics": "0.3.9", + "@firebase/app": "0.6.8", "@firebase/app-types": "0.6.1", - "@firebase/auth": "0.14.7", - "@firebase/database": "0.6.6", - "@firebase/firestore": "1.15.5", - "@firebase/functions": "0.4.47", - "@firebase/installations": "0.4.13", - "@firebase/messaging": "0.6.19", - "@firebase/performance": "0.3.8", + "@firebase/auth": "0.14.8", + "@firebase/database": "0.6.7", + "@firebase/firestore": "1.16.0", + "@firebase/functions": "0.4.48", + "@firebase/installations": "0.4.14", + "@firebase/messaging": "0.6.20", + "@firebase/performance": "0.3.9", "@firebase/polyfill": "0.3.36", - "@firebase/remote-config": "0.1.24", - "@firebase/storage": "0.3.37", + "@firebase/remote-config": "0.1.25", + "@firebase/storage": "0.3.38", "@firebase/util": "0.2.50" } }, @@ -19528,9 +19528,9 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" }, "whatwg-fetch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.1.1.tgz", - "integrity": "sha512-UlBvc5VApYAwNutfXFeuC9Jp3QCMazcqobfNqSK/RghRr3F8b0+i/QELUlEPsHjDHfijio6H5KPJcZwYXhuZsA==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.2.0.tgz", + "integrity": "sha512-SdGPoQMMnzVYThUbSrEvqTlkvC1Ux27NehaJ/GUHBfNrh5Mjg+1/uRyFMwVnxO2MrikMWvWAqUGgQOfVU4hT7w==" }, "which": { "version": "1.3.1", diff --git a/package.json b/package.json index 6f0bd3d5..553257ee 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "array-move": "^2.2.2", "classnames": "^2.2.6", "dotenv": "^8.2.0", - "firebase": "^7.15.5", + "firebase": "^7.16.0", "formik": "^2.1.4", "gatsby": "^2.24.1", "gatsby-image": "^2.4.13", diff --git a/src/components/builder/lists/List.js b/src/components/builder/lists/List.js index 24f92c3b..958f8b24 100644 --- a/src/components/builder/lists/List.js +++ b/src/components/builder/lists/List.js @@ -53,13 +53,9 @@ const List = ({ )} - ); }; diff --git a/src/components/builder/right/sections/Actions.js b/src/components/builder/right/sections/Actions.js index 90750ea6..8ed9a5cd 100644 --- a/src/components/builder/right/sections/Actions.js +++ b/src/components/builder/right/sections/Actions.js @@ -1,25 +1,52 @@ -import React, { memo } from 'react'; +import React, { memo, useContext } from 'react'; import { MdImportExport } from 'react-icons/md'; +import { clone } from 'lodash'; import Heading from '../../../shared/Heading'; import Button from '../../../shared/Button'; import styles from './Actions.module.css'; import Input from '../../../shared/Input'; +import ModalContext from '../../../../contexts/ModalContext'; +import { useSelector } from '../../../../contexts/ResumeContext'; const Actions = () => { + const state = useSelector(); + const { emitter, events } = useContext(ModalContext); + + const handleImport = () => emitter.emit(events.IMPORT_MODAL); + + const handleExportToJson = () => { + const backupObj = clone(state); + delete backupObj.id; + const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent( + JSON.stringify(backupObj), + )}`; + const dlAnchor = document.getElementById('downloadAnchor'); + dlAnchor.setAttribute('href', dataStr); + dlAnchor.setAttribute('download', `RxResume_${state.id}.json`); + dlAnchor.click(); + }; + + const getSharableUrl = () => { + const shareId = state.id.split('-')[0]; + return `https://rxresu.me/r/${shareId}`; + }; + return (
Actions
-
Import from Other Sources
+
Import Your Resume

You can import your information from various sources like JSON Resume - or your LinkedIn profile to autofill most of the data for your resume. + or your LinkedIn to autofill most of the data for your resume.

-
@@ -32,21 +59,27 @@ const Actions = () => {

- +
+ + + Download Exported JSON +
Share Your Resume

- The link below will be accessible publicly if you choose, and you can - share the latest version of your resume to anyone in the world. + The link below will be accessible publicly if you choose to share it, + and viewers would see the latest version of your resume at any time.

- {}} /> + {}} />
@@ -59,7 +92,7 @@ const Actions = () => {

-
@@ -73,7 +106,7 @@ const Actions = () => {

-
diff --git a/src/components/builder/right/sections/Colors.js b/src/components/builder/right/sections/Colors.js index 54492cd7..ab1584dd 100644 --- a/src/components/builder/right/sections/Colors.js +++ b/src/components/builder/right/sections/Colors.js @@ -1,7 +1,7 @@ /* eslint-disable jsx-a11y/control-has-associated-label */ import React, { memo } from 'react'; import { useDispatch } from '../../../../contexts/ResumeContext'; -import colors from '../../../../data/colors'; +import colorOptions from '../../../../data/colorOptions'; import { handleKeyUp } from '../../../../utils'; import Heading from '../../../shared/Heading'; import Input from '../../../shared/Input'; @@ -25,7 +25,7 @@ const Colors = () => { Colors
- {colors.map((color) => ( + {colorOptions.map((color) => (
{ Fonts
- {fonts.map((x) => ( + {fontOptions.map((x) => (
{ Templates
- {templates.map((x) => ( + {templateOptions.map((x) => (
{
{user ? ( - ) : (
diff --git a/src/components/shared/Button.js b/src/components/shared/Button.js index 1be02e03..aadf13eb 100644 --- a/src/components/shared/Button.js +++ b/src/components/shared/Button.js @@ -3,7 +3,15 @@ import React, { memo } from 'react'; import { handleKeyUp } from '../../utils'; import styles from './Button.module.css'; -const Button = ({ icon, title, onClick, outline, className, isLoading }) => { +const Button = ({ + icon, + onClick, + outline, + children, + className, + isLoading, + isDelete, +}) => { const Icon = icon; return ( @@ -12,10 +20,11 @@ const Button = ({ icon, title, onClick, outline, className, isLoading }) => { onClick={isLoading ? undefined : onClick} className={cx(styles.container, className, { [styles.outline]: outline, + [styles.delete]: isDelete, })} > {icon && } - {isLoading ? 'Loading...' : title} + {isLoading ? 'Loading...' : children} ); }; diff --git a/src/components/shared/Button.module.css b/src/components/shared/Button.module.css index 0d613204..3fdf744f 100644 --- a/src/components/shared/Button.module.css +++ b/src/components/shared/Button.module.css @@ -29,3 +29,15 @@ .container.outline:focus { @apply outline-none; } + +.container.delete { + @apply bg-red-600 border-red-600 text-white; +} + +.container.delete:hover { + @apply bg-red-700 border-red-700; +} + +.container.delete:focus { + @apply outline-none; +} \ No newline at end of file diff --git a/src/components/shared/Input.js b/src/components/shared/Input.js index 512ded05..9ac96d8f 100644 --- a/src/components/shared/Input.js +++ b/src/components/shared/Input.js @@ -4,7 +4,6 @@ import React, { memo, useEffect, useState } from 'react'; import { FaAngleDown } from 'react-icons/fa'; import { MdClose, MdOpenInNew } from 'react-icons/md'; import { v4 as uuidv4 } from 'uuid'; -import { IoIosCopy } from 'react-icons/io'; import { useDispatch, useSelector } from '../../contexts/ResumeContext'; import { handleKeyUp } from '../../utils'; import styles from './Input.module.css'; diff --git a/src/constants/ModalEvents.js b/src/constants/ModalEvents.js index c491d19f..8bc8c407 100644 --- a/src/constants/ModalEvents.js +++ b/src/constants/ModalEvents.js @@ -10,6 +10,7 @@ const ModalEvents = { HOBBY_MODAL: 'hobby_modal', LANGUAGE_MODAL: 'language_modal', REFERENCE_MODAL: 'reference_modal', + IMPORT_MODAL: 'import_modal', }; export default ModalEvents; diff --git a/src/contexts/DatabaseContext.js b/src/contexts/DatabaseContext.js index 0c989c47..32940f93 100644 --- a/src/contexts/DatabaseContext.js +++ b/src/contexts/DatabaseContext.js @@ -14,18 +14,18 @@ const DEBOUNCE_WAIT_TIME = 4000; const defaultState = { isOffline: false, isUpdating: false, + createResume: () => {}, + deleteResume: () => {}, getResume: async () => {}, getResumes: async () => {}, - createResume: () => {}, updateResume: async () => {}, debouncedUpdateResume: async () => {}, - debouncedUpdateMetadata: async () => {}, - deleteResume: () => {}, }; const DatabaseContext = createContext(defaultState); const DatabaseProvider = ({ children }) => { + const [resumeId, setResumeId] = useState(false); const [isOffline, setOffline] = useState(false); const [isUpdating, setUpdating] = useState(false); const { user } = useContext(UserContext); @@ -38,6 +38,7 @@ const DatabaseProvider = ({ children }) => { }, []); const getResume = async (id) => { + setResumeId(id); const snapshot = await firebase .database() .ref(`users/${user.uid}/resumes/${id}`) @@ -71,13 +72,11 @@ const DatabaseProvider = ({ children }) => { }; const updateResume = async (resume) => { - const { id } = resume; - setUpdating(true); await firebase .database() - .ref(`users/${user.uid}/resumes/${id}`) + .ref(`users/${user.uid}/resumes/${resumeId}`) .update({ ...resume, updatedAt: firebase.database.ServerValue.TIMESTAMP, @@ -88,22 +87,6 @@ const DatabaseProvider = ({ children }) => { 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(); }; @@ -116,9 +99,8 @@ const DatabaseProvider = ({ children }) => { getResume, createResume, updateResume, - debouncedUpdateResume, - debouncedUpdateMetadata, deleteResume, + debouncedUpdateResume, }} > {children} diff --git a/src/contexts/ResumeContext.js b/src/contexts/ResumeContext.js index 208d24a9..a9669f75 100644 --- a/src/contexts/ResumeContext.js +++ b/src/contexts/ResumeContext.js @@ -90,6 +90,11 @@ const ResumeProvider = ({ children }) => { debouncedUpdateResume(newState); return newState; + case 'on_import': + newState = { id: state.id, ...payload }; + debouncedUpdateResume(newState); + return newState; + case 'set_data': return payload; diff --git a/src/data/colors.js b/src/data/colorOptions.js similarity index 80% rename from src/data/colors.js rename to src/data/colorOptions.js index 29051447..bd231af7 100644 --- a/src/data/colors.js +++ b/src/data/colorOptions.js @@ -1,4 +1,4 @@ -const colors = [ +const colorOptions = [ '#f44336', '#E91E63', '#9C27B0', @@ -17,4 +17,4 @@ const colors = [ '#FF5722', ]; -export default colors; +export default colorOptions; diff --git a/src/data/fonts.js b/src/data/fontOptions.js similarity index 70% rename from src/data/fonts.js rename to src/data/fontOptions.js index 1fba06e1..50992055 100644 --- a/src/data/fonts.js +++ b/src/data/fontOptions.js @@ -1,4 +1,4 @@ -const fonts = [ +const fontOptions = [ 'Lato', 'Montserrat', 'Nunito', @@ -9,4 +9,4 @@ const fonts = [ 'Titillium Web', ]; -export default fonts; +export default fontOptions; diff --git a/src/data/templates.js b/src/data/templateOptions.js similarity index 78% rename from src/data/templates.js rename to src/data/templateOptions.js index a70bbb75..8bcda2f7 100644 --- a/src/data/templates.js +++ b/src/data/templateOptions.js @@ -1,4 +1,4 @@ -const templates = [ +const templateOptions = [ { id: 'onyx', name: 'Onyx', @@ -11,4 +11,4 @@ const templates = [ }, ]; -export default templates; +export default templateOptions; diff --git a/src/modals/AuthModal.js b/src/modals/AuthModal.js index c2bd96e3..164b7b5b 100644 --- a/src/modals/AuthModal.js +++ b/src/modals/AuthModal.js @@ -39,23 +39,25 @@ const AuthModal = () => { const loggedInAction = ( <> - + ); const loggedOutAction = ( - ); return (

{getMessage()}

diff --git a/src/modals/BaseModal.js b/src/modals/BaseModal.js index 121825e5..b4b82cf4 100644 --- a/src/modals/BaseModal.js +++ b/src/modals/BaseModal.js @@ -9,7 +9,7 @@ import { handleKeyUp } from '../utils'; import styles from './BaseModal.module.css'; const BaseModal = forwardRef( - ({ title, state, children, action, onDestroy }, ref) => { + ({ title, state, children, action, hideActions = false, onDestroy }, ref) => { const [open, setOpen] = state; const handleClose = () => { @@ -44,16 +44,15 @@ const BaseModal = forwardRef(
{children}
-
- - {action} -
+ {action} +
+ )}
diff --git a/src/modals/DataModal.js b/src/modals/DataModal.js index 960582c3..fe044f46 100644 --- a/src/modals/DataModal.js +++ b/src/modals/DataModal.js @@ -79,7 +79,9 @@ const DataModal = ({ : title.create; const submitAction = ( - ); const onDestroy = () => { diff --git a/src/modals/ModalRegistrar.js b/src/modals/ModalRegistrar.js index 0205c786..68133d99 100644 --- a/src/modals/ModalRegistrar.js +++ b/src/modals/ModalRegistrar.js @@ -5,6 +5,7 @@ import AwardModal from './sections/AwardModal'; import CertificateModal from './sections/CertificateModal'; import EducationModal from './sections/EducationModal'; import HobbyModal from './sections/HobbyModal'; +import ImportModal from './sections/ImportModal'; import LanguageModal from './sections/LanguageModal'; import ReferenceModal from './sections/ReferenceModal'; import SkillModal from './sections/SkillModal'; @@ -25,6 +26,7 @@ const ModalRegistrar = () => { + ); }; diff --git a/src/modals/sections/ImportModal.js b/src/modals/sections/ImportModal.js new file mode 100644 index 00000000..c5954b84 --- /dev/null +++ b/src/modals/sections/ImportModal.js @@ -0,0 +1,95 @@ +import React, { memo, useContext, useEffect, useState, useRef } from 'react'; +import { Tooltip } from '@material-ui/core'; +import ModalContext from '../../contexts/ModalContext'; +import BaseModal from '../BaseModal'; +import Button from '../../components/shared/Button'; +import { useDispatch } from '../../contexts/ResumeContext'; + +const ImportModal = () => { + const fileInputRef = useRef(null); + const [open, setOpen] = useState(false); + const dispatch = useDispatch(); + + const { emitter, events } = useContext(ModalContext); + + useEffect(() => { + const unbind = emitter.on(events.IMPORT_MODAL, () => setOpen(true)); + + return () => unbind(); + }, [emitter, events]); + + const importReactiveResumeJson = (event) => { + const fr = new FileReader(); + fr.addEventListener('load', () => { + const payload = JSON.parse(fr.result); + dispatch({ type: 'on_import', payload }); + setOpen(false); + }); + fr.readAsText(event.target.files[0]); + }; + + return ( + +
+
+ Import from Reactive Resume +
+ +

+ Reactive Resume has it's own schema format to make the most of + all the customizable capabilities it has to offer. If you'd like + to import a backup of your resume made with this app, just upload the + file using the button below. +

+ + + +
+ +
+ +
+
Import from JSON Resume
+ +

+ JSON Resume is an open standard + for resume schema structure. If you are one of the many enthusiasts + who have their resume ready in this format, all it takes it just one + click to get started with Reactive Resume. +

+ + +
+ +
+
+
+ +
+ +
+
Import from LinkedIn
+ +

+ You can import a JSON that was exported from Reactive Resume by + clicking on the button below and selecting the appropriate file. +

+ + +
+ +
+
+
+
+ ); +}; + +export default memo(ImportModal);