{"id":24333376,"url":"https://github.com/ericgitangu/react-portfolio-app","last_synced_at":"2026-04-19T08:33:13.855Z","repository":{"id":216704436,"uuid":"742096351","full_name":"ericgitangu/React-Portfolio-App","owner":"ericgitangu","description":null,"archived":false,"fork":false,"pushed_at":"2024-05-02T16:28:17.000Z","size":8468,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-11T13:48:19.137Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ericgitangu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-11T18:51:27.000Z","updated_at":"2024-01-19T19:36:03.000Z","dependencies_parsed_at":"2024-05-02T17:39:17.961Z","dependency_job_id":"35054623-ee86-4b09-b3c9-f0a918508c01","html_url":"https://github.com/ericgitangu/React-Portfolio-App","commit_stats":null,"previous_names":["ericgitangu/react-portfolio-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ericgitangu/React-Portfolio-App","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgitangu%2FReact-Portfolio-App","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgitangu%2FReact-Portfolio-App/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgitangu%2FReact-Portfolio-App/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgitangu%2FReact-Portfolio-App/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ericgitangu","download_url":"https://codeload.github.com/ericgitangu/React-Portfolio-App/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgitangu%2FReact-Portfolio-App/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32000329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-18T03:15:17.934Z","updated_at":"2026-04-19T08:33:13.839Z","avatar_url":"https://github.com/ericgitangu.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Instructions\n\n## Task\n\nIn this final lab, you are going to create a portfolio page for yourself. You will be using the skills you have learned in this course to create a page that showcases your work.\nThe portfolio page will be a single page that will contain the following sections:\n\n- A header with external links to social media accounts and internal links to other sections of the page\n- A landing section with an avatar picture and a short bio\n- A section to display your featured projects as cards in a grid fashion\n- A contact me section with a form to allow visitors to contact you\n\nHere you will have the opportunity to use some popular open source libraries that will help you to have a more polished and professional looking page.\n\nBefore proceeding further, let's provide an introduction to the libraries you will be using.\n\n### Libraries\n\n#### Chakra UI\n\nChakra UI comes pre-configured with this lab, so you don't have to worry about installing it or setting it up.\n\nThe components from this library you will need to use are already imported from the `@chakra-ui/react` package at the top of each corresponding file.\nIf you don't see a component already imported, it's because you probably won't need it.\nIn any case, feel free to check their official [documentation](https://chakra-ui.com/docs/components) to see all the components at your disposal and their corresponding props.\n\n#### Formik and Yup\n\nThe Formik library is already set up in the project as well, so no extra configuration is needed.\nIn this lab, you will be only using the `useFormik` hook from the Formik library, as well as the global `Yup` object to define the Contact Me form validation rules.\n\nThe form UI will be implemented using Chakra UI components.\n\nBefore you begin, if you run `npm start` and view the app in the browser, you'll notice that the starting React app works as is.\n\nThe app outputs a page with an empty header, 3 different full-height sections and a footer.\nEvery section has a different background color. The first 2 sections will be empty and the third section will contain all the UI elements for the Contact Me form.\n\n![initial_app](screenshots/initial_app.png)\n\n## Steps\n\nOnce you open the code lab, you need to install the *Chakra UI* and other referenced libraries by running the `npm install` command from the built-in terminal in the code lab. To toggle the built-in terminal, you need to click the View menu item, then choose the Terminal in the dropdown.\n\nOnce the terminal is open (visible), you can run the `npm install` command. This will install all the required missing dependencies, so that you can begin working on the task.\n\n### **Step 1**\n\nOpen `Header.js` file. You will see a header component with black background, but no content.\n\na) **Add external social media links to the header on the left side of the page**.\n\nThe implementation should be placed inside the first `nav` element. The data is already provided in the `socials` array at the top of the file.\n\nUse the `HStack` component to stack the links horizontally.\nEach social should be a `a` tag with a `href` attribute pointing to the corresponding social media page. The `a` tag should have as children a `FontAwesomeIcon` component, which is already imported for you.\n\nThe `FontAwesomeIcon` component takes 2 props:\n\n- `icon`: The icon to be displayed. In this case, you should use the `icon` prop from the `social` object.\n- `size`: The size of the icon. You can use the `2x` value.\n\nYou can check below an example of how to render it:\n\n`\u003cFontAwesomeIcon icon=\"fab\" size=\"2x\" /\u003e`\n\nb) **Add internal links to the Projects section and Contact Me section**\n\nEach link should be a `a` tag. Each `a` tag should have as children the name of the section: \"Contact Me\" and \"Projects\".\nWhen clicking on the link, the url should show the corresponding section. For example, when clicking on the \"Contact Me\" link, the url path should be `/#contact-me`.\nAlso, the click should scroll to the corresponding section with a smooth animation. The code for that has been provided for you via the `handleClick` function. You need to hook that function with the `a` tag `onClick` event.\nBear in mind the Projects section has an id called `projects-section` and the Contact Me section has an id called `contactme-section`.\n\nAvoid any key related warnings when opening the console.\n\nThe final header UI should look like below:\n\n![header_ui](screenshots/image8.png)\n\n### **Step 2**\n\nOpen the `LandingSection.js` file. Implement the below UI to provide a landing section for the app with an avatar, a greeting and a brief role description.\nFor the data, use the variables provided at the top of the file (`greeting`, `bio1` and `bio2`) and not personal data.\nFor the avatar you can use the next url: `https://i.pravatar.cc/150?img=7`\nAll the components you need have been already imported for you.\n\n![landing_section](screenshots/image3.png)\n\n### **Step 3**\n\nOpen the `ProjectsSection.js` component. This component is already implemented, however the `Card` component that it uses to display information about each project it's not.\nThe `ProjectsSection` component already defines a `projects` array with the data for each project and that information is passed to each `Card` component as props.\n\nOpen the `Card.js` component and implement the UI for the card. Each card should look like the image below:\n\n![card_ui](screenshots/image2.png)\n\nYou can use the following components from Chakra UI that have been already imported for you:\n\n- HStack,\n- VStack,\n- Image,\n- Heading,\n- Text,\n\nFor the right arrow, use the below component. The necessary imports are already provided for you as well.\n`\u003cFontAwesomeIcon icon={faArrowRight} size=\"1x\" /\u003e`\n\nAvoid any key related warnings when opening the console.\n\n### **Step 4**\n\nOpen the `ContactMeSection.js` component. Implement the remaining requirements of the form according to the below specifications.\n\nThe form contains 4 input fields: name, email address, type of enquiry and message.\n\nThe whole UI of the form is defined for you. You need to implement some missing business logic.\n\n![contact_form](screenshots/image4.png)\n\na) **Add the proper configuration to the `useFormik` hook, passing an object with 3 properties**: `initialValues`, `onSubmit` and `validationSchema`.\n\nThe `initialValues` object should have the following fields:\n\n- `firstName`: The name of the user\n- `email`: The email of the user\n- `type`: 'hireMe' | 'openSource' | 'other'\n- `comment`: A message from the user\n\nThe `onSubmit` function should perform an API call by using the `submit` helper from `useSubmit` hook.\nInspect the `useSubmit` custom hook to see the arguments the `submit` function expects.\n\nThe `validationSchema` should be a Yup schema that validates the form fields. The validation rules are as follows:\n\n- `firstName`: required field. Otherwise, the error message should be \"Required\".\n- `email`: required field and a valid email. If empty, the error message should be \"Required\". If not a valid email, the error message should be \"Invalid email address\".\n- `type`: Optional field\n- `comment`: required field and with a minimum of 25 characters. If empty, the error message should be \"Required\". If less than 25 characters, the error message should be \"Must be at least 25 characters\".\n\nb) **Make the `Input` components from Chakra UI controlled components**.\n\n`useFormik` hook returns an object with a function called `getFieldProps` that when called, returns an object with the necessary props to make the input controlled.\n\nc) **Show the error messages for each field when the field is touched and the validation fails**.\n\nEach field is grouped in a `FormControl` component. The `FormControl` component takes a `isInvalid` prop that you can use to show the error message.\n\nThe `isInvalid` prop should be `true` when the field is touched and the validation fails.\n\nThe `FormErrorMessage` component from Chakra UI should display the corresponding error message if the `isInvalid` prop from the parent `FormControl` component is true.\n\nBelow is an example of how the UI should look like when the validation fails for the `firstName` field:\n\n![error_message](screenshots/image5.png)\n\nd) **Connect the `form` onSubmit prop with Formik's `handleSubmit` function**.\n\nMake sure the default HTML form behaviour is prevented when a submission occurs.\n\ne) **Show an alert when the form is submitted successfully**.\n\nYou need to listen to changes in the `response` object from the `useSubmit` hook. Also, when the form is submitted, a loading indicator should be shown in the Submit button. You can use the `isLoading` property from the `useSubmit` hook.\n\nThe `useSubmit` hook is implemented in a way that 50% of the times it will return a successful response and 50% of the times it will return an error response.\n\nThe `response` object from the API has 2 properties:\n\n- `type`: 'success' | 'error'\n- `message`: Extra contextual information about the response\n\nYou can use the provided `useAlertContext` hook to show the alert. The hook returns a function named `onOpen` that you can call to display it.\n\nCheck the `alertContext.js` file to see the arguments the `onOpen` function expects.\n\nIf the response is successful, the alert should display in its content the first name of the user, according to the value typed in the form 1st field, so make sure you are passing the right arguments to the `submit` function returned from the `useSubmit` hook.\n\nIn addition, the form has to be reset if the response is successful. For that use the `resetForm` function from the object returned from the `useFormik` hook.\n\nThis is how the UI should look for both cases:\n\n![success_alert](screenshots/image6.png)\n\n![error_alert](screenshots/image7.png)\n\n### **Step 5 (bonus)**\n\nImplement a header show/hide animation depending on the scroll direction.\nThe header should slide up with some animation and be hidden when scrolling down the page.\nWhen scrolling up, the header should slide down and be visible.\n\nFor that, the outermost Box component has some transition properties already defined. Your logic should change the `transform` property of the underlying `Box` DOM element depending on the scroll direction.\n\nWhen scrolling up, the `transform` style property from the `Box` DOM element should be `translateY(0)`.\nWhen scrolling down, the `transform` style property from the `Box` DOM element should be `translateY(-200px)`.\n\nHere are some of the elements you may need for the implementation:\n\n- The `useEffect` hook\n- The `useRef` hook\n- Setting up listeners for the scroll event `window.addEventListener('scroll', handleScroll)`\n- Removing listeners for the scroll event: `window.removeEventListener('scroll', handleScroll)`\n- Keeping track of the previous scroll position in a variable\n\n![header_animation](screenshots/header_animation.gif)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericgitangu%2Freact-portfolio-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fericgitangu%2Freact-portfolio-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericgitangu%2Freact-portfolio-app/lists"}