mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-16 01:32:02 +10:00
- implement "Import from JSON Resume" feature
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
import arrayMove from 'array-move';
|
import arrayMove from 'array-move';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import {
|
import {
|
||||||
clone,
|
clone,
|
||||||
findIndex,
|
findIndex,
|
||||||
@ -123,6 +124,86 @@ const ResumeProvider = ({ children }) => {
|
|||||||
debouncedUpdateResume(newState);
|
debouncedUpdateResume(newState);
|
||||||
return newState;
|
return newState;
|
||||||
|
|
||||||
|
case 'on_import_jsonresume':
|
||||||
|
temp = clone(state);
|
||||||
|
newState = initialState;
|
||||||
|
newState.id = temp.id;
|
||||||
|
newState.user = temp.user;
|
||||||
|
newState.name = temp.name;
|
||||||
|
newState.preview = temp.preview;
|
||||||
|
newState.createdAt = temp.createdAt;
|
||||||
|
newState.updatedAt = temp.updatedAt;
|
||||||
|
newState.profile = {
|
||||||
|
address: {
|
||||||
|
city: payload.basics.location.city,
|
||||||
|
line1: payload.basics.location.address,
|
||||||
|
line2: payload.basics.location.region,
|
||||||
|
pincode: payload.basics.location.postalCode,
|
||||||
|
},
|
||||||
|
email: payload.basics.email,
|
||||||
|
firstName: payload.basics.name,
|
||||||
|
phone: payload.basics.phone,
|
||||||
|
photograph: payload.basics.picture,
|
||||||
|
subtitle: payload.basics.label,
|
||||||
|
website: payload.basics.website,
|
||||||
|
};
|
||||||
|
newState.social.items = payload.basics.profiles.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
network: x.network,
|
||||||
|
username: x.username,
|
||||||
|
url: x.url,
|
||||||
|
}));
|
||||||
|
newState.objective.body = payload.basics.summary;
|
||||||
|
newState.work.items = payload.work.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
company: x.company,
|
||||||
|
endDate: x.endDate,
|
||||||
|
position: x.position,
|
||||||
|
startDate: x.startDate,
|
||||||
|
summary: x.summary,
|
||||||
|
website: x.website,
|
||||||
|
}));
|
||||||
|
newState.education.items =
|
||||||
|
payload.education &&
|
||||||
|
payload.education.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
degree: x.studyType,
|
||||||
|
endDate: x.endDate,
|
||||||
|
field: x.area,
|
||||||
|
gpa: x.gpa,
|
||||||
|
institution: x.institution,
|
||||||
|
startDate: x.startDate,
|
||||||
|
summary: x.courses.join('\n'),
|
||||||
|
}));
|
||||||
|
newState.awards.items = payload.awards.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
awarder: x.awarder,
|
||||||
|
date: x.date,
|
||||||
|
summary: x.summary,
|
||||||
|
title: x.title,
|
||||||
|
}));
|
||||||
|
newState.skills.items = payload.skills.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
level: 'Fundamental Awareness',
|
||||||
|
name: x.name,
|
||||||
|
}));
|
||||||
|
newState.hobbies.items = payload.interests.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
name: x.name,
|
||||||
|
}));
|
||||||
|
newState.languages.items = payload.languages.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
name: x.language,
|
||||||
|
fluency: x.fluency,
|
||||||
|
}));
|
||||||
|
newState.references.items = payload.references.map((x) => ({
|
||||||
|
id: uuidv4(),
|
||||||
|
name: x.name,
|
||||||
|
summary: x.reference,
|
||||||
|
}));
|
||||||
|
debouncedUpdateResume(newState);
|
||||||
|
return newState;
|
||||||
|
|
||||||
case 'set_data':
|
case 'set_data':
|
||||||
newState = payload;
|
newState = payload;
|
||||||
debouncedUpdateResume(newState);
|
debouncedUpdateResume(newState);
|
||||||
|
|||||||
@ -185,7 +185,6 @@
|
|||||||
"lastName": "Pillai",
|
"lastName": "Pillai",
|
||||||
"phone": "+91 98453 36113",
|
"phone": "+91 98453 36113",
|
||||||
"photograph": "https://i.imgur.com/2dmLSCT.jpg",
|
"photograph": "https://i.imgur.com/2dmLSCT.jpg",
|
||||||
"profile": "",
|
|
||||||
"subtitle": "Full Stack Web Developer",
|
"subtitle": "Full Stack Web Developer",
|
||||||
"website": "amruthpillai.com"
|
"website": "amruthpillai.com"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
"city": "",
|
"city": "",
|
||||||
"pincode": ""
|
"pincode": ""
|
||||||
},
|
},
|
||||||
"profile": "",
|
|
||||||
"website": "",
|
"website": "",
|
||||||
"email": ""
|
"email": ""
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"additionalProperties": false,
|
"$id": "http://json-schema.org/draft-04/schema#",
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"iso8601": {
|
"iso8601": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -9,11 +9,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"$schema": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "link to the version of the schema that can validate the resume",
|
|
||||||
"format": "uri"
|
|
||||||
},
|
|
||||||
"basics": {
|
"basics": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema",
|
"$schema": "http://json-schema.org/draft-07/schema",
|
||||||
"$id": "http://example.com/example.json",
|
"$id": "http://json-schema.org/draft-07/schema",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "The root schema",
|
"title": "The root schema",
|
||||||
"description": "The root schema comprises the entire JSON document.",
|
"description": "The root schema comprises the entire JSON document.",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import Button from '../../components/shared/Button';
|
|||||||
import ModalContext from '../../contexts/ModalContext';
|
import ModalContext from '../../contexts/ModalContext';
|
||||||
import { useDispatch } from '../../contexts/ResumeContext';
|
import { useDispatch } from '../../contexts/ResumeContext';
|
||||||
import reactiveResumeSchema from '../../data/schema/reactiveResume.json';
|
import reactiveResumeSchema from '../../data/schema/reactiveResume.json';
|
||||||
|
import jsonResumeSchema from '../../data/schema/jsonResume.json';
|
||||||
import BaseModal from '../BaseModal';
|
import BaseModal from '../BaseModal';
|
||||||
|
|
||||||
const ImportModal = () => {
|
const ImportModal = () => {
|
||||||
@ -39,6 +40,21 @@ const ImportModal = () => {
|
|||||||
fr.readAsText(event.target.files[0]);
|
fr.readAsText(event.target.files[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const importJsonResume = (event) => {
|
||||||
|
const fr = new FileReader();
|
||||||
|
fr.addEventListener('load', () => {
|
||||||
|
const payload = JSON.parse(fr.result);
|
||||||
|
const valid = ajv.validate(jsonResumeSchema, payload);
|
||||||
|
if (!valid) {
|
||||||
|
ajv.errors.forEach((x) => toast.error(`Invalid Data: ${x.message}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch({ type: 'on_import_jsonresume', payload });
|
||||||
|
setOpen(false);
|
||||||
|
});
|
||||||
|
fr.readAsText(event.target.files[0]);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseModal
|
<BaseModal
|
||||||
hideActions
|
hideActions
|
||||||
@ -74,11 +90,15 @@ const ImportModal = () => {
|
|||||||
|
|
||||||
<p className="leading-loose">{t('modals.import.jsonResume.text')}</p>
|
<p className="leading-loose">{t('modals.import.jsonResume.text')}</p>
|
||||||
|
|
||||||
<Tooltip title="Coming Soon" placement="right" arrow>
|
<Button className="mt-5" onClick={() => fileInputRef.current.click()}>
|
||||||
<div className="mt-5 inline-block">
|
{t('modals.import.button')}
|
||||||
<Button className="opacity-50">{t('modals.import.button')}</Button>
|
</Button>
|
||||||
</div>
|
<input
|
||||||
</Tooltip>
|
ref={fileInputRef}
|
||||||
|
type="file"
|
||||||
|
className="hidden"
|
||||||
|
onChange={importJsonResume}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr className="my-8" />
|
<hr className="my-8" />
|
||||||
|
|||||||
Reference in New Issue
Block a user