From 5736e89464ce148453378275868b66eb71ca6f1f Mon Sep 17 00:00:00 2001 From: Radu Baston Date: Sun, 18 Jun 2023 17:34:09 +0300 Subject: [PATCH] Switched to using hooks instead of class-based components --- src/App.js | 208 +++++++++++++------------- src/components/About.js | 156 ++++++++++--------- src/components/Experience.js | 154 ++++++++++--------- src/components/Footer.js | 58 ++++--- src/components/Header.js | 149 +++++++++--------- src/components/ProjectDetailsModal.js | 30 ++-- src/components/Projects.js | 115 +++++++------- src/components/Skills.js | 72 +++++---- 8 files changed, 456 insertions(+), 486 deletions(-) diff --git a/src/App.js b/src/App.js index a99f38c84..19daf6bd1 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import $ from "jquery"; import "./App.scss"; import Header from "./components/Header"; @@ -8,135 +8,127 @@ import Experience from "./components/Experience"; import Projects from "./components/Projects"; import Skills from "./components/Skills"; -class App extends Component { +const App = () => { - constructor(props) { - super(); - this.state = { - foo: "bar", - resumeData: {}, - sharedData: {}, - }; - } + const [resumeData, setResumeData] = useState({}); + const [sharedData, setSharedData] = useState({}); - applyPickedLanguage(pickedLanguage, oppositeLangIconId) { - this.swapCurrentlyActiveLanguage(oppositeLangIconId); - document.documentElement.lang = pickedLanguage; - var resumePath = - document.documentElement.lang === window.$primaryLanguage - ? `res_primaryLanguage.json` - : `res_secondaryLanguage.json`; - this.loadResumeFromPath(resumePath); - } - - swapCurrentlyActiveLanguage(oppositeLangIconId) { - var pickedLangIconId = - oppositeLangIconId === window.$primaryLanguageIconId - ? window.$secondaryLanguageIconId - : window.$primaryLanguageIconId; - document - .getElementById(oppositeLangIconId) - .removeAttribute("filter", "brightness(40%)"); - document - .getElementById(pickedLangIconId) - .setAttribute("filter", "brightness(40%)"); - } - - componentDidMount() { - this.loadSharedData(); - this.applyPickedLanguage( - window.$primaryLanguage, - window.$secondaryLanguageIconId - ); - } - - loadResumeFromPath(path) { + const loadSharedData = useCallback(() => { $.ajax({ - url: path, + url: `portfolio_shared_data.json`, dataType: "json", cache: false, success: function (data) { - this.setState({ resumeData: data }); - }.bind(this), + setSharedData(data); + document.title = `${sharedData.basic_info?.name}`; + }, error: function (xhr, status, err) { alert(err); }, }); - } + }, [sharedData, setSharedData]); - loadSharedData() { + const loadResumeFromPath = useCallback((path) => { $.ajax({ - url: `portfolio_shared_data.json`, + url: path, dataType: "json", cache: false, success: function (data) { - this.setState({ sharedData: data }); - document.title = `${this.state.sharedData.basic_info.name}`; - }.bind(this), + setResumeData(data); + }, error: function (xhr, status, err) { alert(err); }, }); - } + }, [setResumeData]); + + const swapCurrentlyActiveLanguage = useCallback((oppositeLangIconId) => { + var pickedLangIconId = + oppositeLangIconId === window.$primaryLanguageIconId + ? window.$secondaryLanguageIconId + : window.$primaryLanguageIconId; + document + .getElementById(oppositeLangIconId) + .removeAttribute("filter", "brightness(40%)"); + document + .getElementById(pickedLangIconId) + .setAttribute("filter", "brightness(40%)"); + }, []); - render() { - return ( -
-
-
-
- this.applyPickedLanguage( - window.$primaryLanguage, - window.$secondaryLanguageIconId - ) - } - style={{ display: "inline" }} - > - -
-
- this.applyPickedLanguage( - window.$secondaryLanguage, - window.$primaryLanguageIconId - ) - } - style={{ display: "inline" }} - > - -
+ const applyPickedLanguage = useCallback((pickedLanguage, oppositeLangIconId) => { + swapCurrentlyActiveLanguage(oppositeLangIconId); + document.documentElement.lang = pickedLanguage; + var resumePath = + document.documentElement.lang === window.$primaryLanguage + ? `res_primaryLanguage.json` + : `res_secondaryLanguage.json`; + loadResumeFromPath(resumePath); + }, [swapCurrentlyActiveLanguage, loadResumeFromPath]); + + useEffect(() => { + loadSharedData(); + applyPickedLanguage( + window.$primaryLanguage, + window.$secondaryLanguageIconId + ); + }, []); + + return ( +
+
+
+
+ applyPickedLanguage( + window.$primaryLanguage, + window.$secondaryLanguageIconId + ) + } + style={{ display: "inline" }} + > + +
+
+ applyPickedLanguage( + window.$secondaryLanguage, + window.$primaryLanguageIconId + ) + } + style={{ display: "inline" }} + > +
- - - - -
- ); - } + + + + +
+
+ ); } export default App; diff --git a/src/components/About.js b/src/components/About.js index c7ff9bbad..b972a9604 100644 --- a/src/components/About.js +++ b/src/components/About.js @@ -1,95 +1,93 @@ -import React, { Component } from "react"; +import React from "react"; import { Icon } from "@iconify/react"; import angularIcon from "@iconify/icons-logos/angular-icon"; import reactIcon from "@iconify/icons-logos/react"; import vueIcon from "@iconify/icons-logos/vue"; -class About extends Component { - render() { - if (this.props.sharedBasicInfo) { - var profilepic = "images/" + this.props.sharedBasicInfo.image; - } - if (this.props.resumeBasicInfo) { - var sectionName = this.props.resumeBasicInfo.section_name.about; - var hello = this.props.resumeBasicInfo.description_header; - var about = this.props.resumeBasicInfo.description; - } +const About = ({sharedBasicInfo, resumeBasicInfo}) => { + if (sharedBasicInfo) { + var profilepic = "images/" + sharedBasicInfo.image; + } + if (resumeBasicInfo) { + var sectionName = resumeBasicInfo.section_name.about; + var hello = resumeBasicInfo.description_header; + var about = resumeBasicInfo.description; + } - return ( -
-
-

- {sectionName} -

-
-
-
- - Avatar placeholder - - - - -
+ return ( +
+
+

+ {sectionName} +

+
+
+
+ + Avatar placeholder + + + +
+
-
-
-
-
- {" "} -  {" "} - {" "} -  {" "} - -
-
-
- {hello} :) -
-
- {about} -
+
+
+
+
+ {" "} +  {" "} + {" "} +  {" "} + +
+
+
+ {hello} :) +
+
+ {about}
-
- ); - } +
+
+ ); } export default About; diff --git a/src/components/Experience.js b/src/components/Experience.js index 6e40f620d..3bd5f1f6a 100644 --- a/src/components/Experience.js +++ b/src/components/Experience.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React from "react"; import { VerticalTimeline, VerticalTimelineElement, @@ -6,91 +6,89 @@ import { import "react-vertical-timeline-component/style.min.css"; import Badge from "react-bootstrap/Badge"; -class Experience extends Component { - render() { - if (this.props.resumeExperience && this.props.resumeBasicInfo) { - var sectionName = this.props.resumeBasicInfo.section_name.experience; - var work = this.props.resumeExperience.map(function (work, i) { - const technologies = work.technologies; - const mainTechnologies = work.mainTech; +const Experience = ({resumeExperience, resumeBasicInfo}) => { + if (resumeExperience && resumeBasicInfo) { + var sectionName = resumeBasicInfo.section_name.experience; + var work = resumeExperience.map(function (work, i) { + const technologies = work.technologies; + const mainTechnologies = work.mainTech; - var mainTech = mainTechnologies.map((technology, i) => { - return ( - - {technology} - - ); - }); - var tech = technologies.map((technology, i) => { - return ( - - {technology} - - ); - }); + var mainTech = mainTechnologies.map((technology, i) => { return ( + + {technology} + + ); + }); + var tech = technologies.map((technology, i) => { + return ( + + {technology} + + ); + }); + return ( + } + key={i} + > +
+ {mainTech} +
+ +

+ {work.title} +

+

+ {work.company} +

+
{tech}
+
+ ); + }); + } + + return ( +
+
+
+

+ + {sectionName} + +

+
+
+
+ + {work} } - key={i} - > -
- {mainTech} -
- -

- {work.title} -

-

- {work.company} -

-
{tech}
-
- ); - }); - } - - return ( -
-
-
-

- - {sectionName} - -

-
-
-
- - {work} - - } - /> - -
-
- ); - } + icon={ + + } + /> +
+
+
+ ); } export default Experience; diff --git a/src/components/Footer.js b/src/components/Footer.js index 00b28970f..3c6a306eb 100644 --- a/src/components/Footer.js +++ b/src/components/Footer.js @@ -1,38 +1,36 @@ -import React, { Component } from "react"; +import React from "react"; -class Footer extends Component { - render() { - if (this.props.sharedBasicInfo) { - var networks = this.props.sharedBasicInfo.social.map(function (network) { - return ( - - - - - - ); - }); - } +const Footer = ({sharedBasicInfo}) => { + if (sharedBasicInfo) { + var networks = sharedBasicInfo.social.map(function (network) { + return ( + + + + + + ); + }); + } - return ( -
-
-
{networks}
+ return ( +
+
+
{networks}
-
-
- - Copyright ©{" "} - {this.props.sharedBasicInfo - ? this.props.sharedBasicInfo.name - : "???"} - -
+
+
+ + Copyright ©{" "} + {sharedBasicInfo + ? sharedBasicInfo.name + : "???"} +
-
- ); - } +
+
+ ); } export default Footer; diff --git a/src/components/Header.js b/src/components/Header.js index b94973a9f..5f5625c5d 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,98 +1,91 @@ -import React, { Component } from "react"; +import React, { useCallback, useState } from "react"; import Typical from "react-typical"; import Switch from "react-switch"; -class Header extends Component { - titles = []; +const Header = ({sharedData}) => { + let titles = []; + const [checked, setChecked] = useState(false); - constructor() { - super(); - this.state = { checked: false }; - this.onThemeSwitchChange = this.onThemeSwitchChange.bind(this); - } - - onThemeSwitchChange(checked) { - this.setState({ checked }); - this.setTheme(); - } - - setTheme() { + const setTheme = useCallback(() => { var dataThemeAttribute = "data-theme"; var body = document.body; var newTheme = body.getAttribute(dataThemeAttribute) === "dark" ? "light" : "dark"; body.setAttribute(dataThemeAttribute, newTheme); - } + }, []); + + const onThemeSwitchChange = useCallback((checkedValue) => { + setChecked(checkedValue); + setTheme(); + }, [setTheme]); - render() { - if (this.props.sharedData) { - var name = this.props.sharedData.name; - this.titles = this.props.sharedData.titles.map(x => [ x.toUpperCase(), 1500 ] ).flat(); - } + if (sharedData) { + var name = sharedData.name; + titles = sharedData.titles.map(x => [ x.toUpperCase(), 1500 ] ).flat(); + } const HeaderTitleTypeAnimation = React.memo( () => { - return + return }, (props, prevProp) => true); - return ( -
-
-
-
- -
-

- -

-
- -
- - } - checkedIcon={ - - } - id="icon-switch" - /> + return ( +
+
+
+
+ +
+

+ +

+
+
+ + } + checkedIcon={ + + } + id="icon-switch" + />
-
- ); - } +
+
+ ); } export default Header; diff --git a/src/components/ProjectDetailsModal.js b/src/components/ProjectDetailsModal.js index a3f27fc64..9fe8665d3 100644 --- a/src/components/ProjectDetailsModal.js +++ b/src/components/ProjectDetailsModal.js @@ -1,19 +1,18 @@ -import React, { Component } from "react"; +import React from "react"; import { Modal } from "react-bootstrap"; import AwesomeSlider from "react-awesome-slider"; import AwesomeSliderStyles from "../scss/light-slider.scss"; import AwesomeSliderStyles2 from "../scss/dark-slider.scss"; import "react-awesome-slider/dist/custom-animations/scale-out-animation.css"; -class ProjectDetailsModal extends Component { - render() { - if (this.props.data) { - const technologies = this.props.data.technologies; - const images = this.props.data.images; - var title = this.props.data.title; - var description = this.props.data.description; - var url = this.props.data.url; - if (this.props.data.technologies) { - var tech = technologies.map((icons, i) => { + + +const ProjectDetailsModal = ({show, data, onHide}) => { + if (data) { + var title = data.title; + var description = data.description; + var url = data.url; + if (data.technologies) { + var tech = data.technologies.map((icons, i) => { return (
  • @@ -28,8 +27,8 @@ class ProjectDetailsModal extends Component {
  • ); }); - if (this.props.data.images) { - var img = images.map((elem, i) => { + if (data.images) { + var img = data.images.map((elem, i) => { return
    ; }); } @@ -37,13 +36,13 @@ class ProjectDetailsModal extends Component { } return ( - +
    @@ -101,7 +100,6 @@ class ProjectDetailsModal extends Component {
    ); - } } export default ProjectDetailsModal; diff --git a/src/components/Projects.js b/src/components/Projects.js index 4eb73a83b..66722019a 100644 --- a/src/components/Projects.js +++ b/src/components/Projects.js @@ -1,70 +1,65 @@ -import React, { Component } from "react"; +import React, { useCallback, useState } from "react"; import ProjectDetailsModal from "./ProjectDetailsModal"; -class Projects extends Component { - constructor(props) { - super(props); - this.state = { - deps: {}, - detailsModalShow: false, - }; - } +const Projects = ({resumeProjects, resumeBasicInfo}) => { - render() { - let detailsModalShow = (data) => { - this.setState({ detailsModalShow: true, deps: data }); - }; + const [deps, setDeps] = useState({}); + const [detailsModalShow, setDetailsModalShow] = useState(false); - let detailsModalClose = () => this.setState({ detailsModalShow: false }); - if (this.props.resumeProjects && this.props.resumeBasicInfo) { - var sectionName = this.props.resumeBasicInfo.section_name.projects; - var projects = this.props.resumeProjects.map(function (projects) { - return ( -
    - -
    detailsModalShow(projects)}> -
    - projectImages - {projects.startDate} -
    -

    - {projects.title} -

    -
    -
    -
    -
    - ); - }); - } + const detailsModalDisplay = useCallback((data) => { + setDetailsModalShow(true); + setDeps(data); + }, [setDetailsModalShow, setDeps]); - return ( -
    -
    -

    - {sectionName} -

    -
    -
    {projects}
    -
    - + let detailsModalClose = useCallback(() => setDetailsModalShow(false), [setDetailsModalShow]); + if (resumeProjects && resumeBasicInfo) { + var sectionName = resumeBasicInfo.section_name.projects; + var projects = resumeProjects.map(function (projects) { + return ( +
    + +
    detailsModalDisplay(projects)}> +
    + projectImages + {projects.startDate} +
    +

    + {projects.title} +

    +
    +
    +
    -
    - ); + ); + }); } + + return ( +
    +
    +

    + {sectionName} +

    +
    +
    {projects}
    +
    + +
    +
    + ); } export default Projects; diff --git a/src/components/Skills.js b/src/components/Skills.js index ddd6c14d7..52e8e598d 100644 --- a/src/components/Skills.js +++ b/src/components/Skills.js @@ -1,44 +1,42 @@ -import React, { Component } from "react"; +import React from "react"; -class Skills extends Component { - render() { - if (this.props.sharedSkills && this.props.resumeBasicInfo) { - var sectionName = this.props.resumeBasicInfo.section_name.skills; - var skills = this.props.sharedSkills.icons.map(function (skills, i) { - return ( -
  • - -
    - -

    - {skills.name} -

    -
    -
    -
    -
  • - ); - }); - } +const Skills = ({sharedSkills, resumeBasicInfo}) => { + if (sharedSkills && resumeBasicInfo) { + var sectionName = resumeBasicInfo.section_name.skills; + var skills = sharedSkills.icons.map(function (skills, i) { + return ( +
  • + +
    + +

    + {skills.name} +

    +
    +
    +
    +
  • + ); + }); + } - return ( -
    + return ( +
    +
    -
    -

    - {sectionName} -

    -
    -
    -
      {skills}
    -
    +

    + {sectionName} +

    -
    - ); - } +
    +
      {skills}
    +
    +
    + + ); } export default Skills;