Skip to content
  • Unlock Pro
  • Log in with GitHub
Solution
Submitted over 3 years ago

Invoice App - ReactJS, Styled-Components, Framer Motion, Webpack

tediko•6,700
@tediko
A solution to the Invoice app challenge
View live sitePreview (opens in new tab)View codeCode (opens in new tab)

Solution retrospective


Hello👋!

This is an invoicing application build with ReactJS and styled-components. The application is used to manage invoices and allows the user to create, read, update, filter by status and delete invoices. There is an option in the app to switch between a dark and a light theme. All transitions are smoothly displayed by using Framer Motion library to create animations. It was by far the largest and most comprehensive project I have done so far. It showed me how important it is to plan so that you don't have to change things that previously worked well in the middle of the project. A valuable lesson!

  • The first time I used useReducer hook to manage application state. I noticed that my state logic getting more complex as the few elements of my state relies on the value of another element of my state. Read More
  • Together with useReducer, the useContext hook turned out to be handy. It allowed me to create common data that can be accessed throughout the component hierarchy without passing the props down manually to each level which in turn allowed me to avoid Prop drilling (also called "threading") that is the process you have to go through to get data to parts of the React Component tree. Read More(1). Read More(2)
  • In order to create a theme switcher and provide colors for components I used styled-components <ThemeProvider> wrapper component. By leveraging the theme provider I only need to write my styles in one single object and invoke them in any component that is a descendant of that provider. Read More
  • When creating the form I learned what Controlled Component is. In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState(). Then the React component that renders a form also controls what happens in that form on subsequent user input. Read More
  • To make application more ADA compliant (which means the website should be entirely accessible using just keyboard) I prevent focus go outside the modal once the modal is opened. In this case, the focus trap turns on when the form or modal with invoice deletion/status change is opened. In order to create an accessible modal I followed this great tutorial that follow the WAI-ARIA Practices.
  • To animate the pages transitions and modals I used Framer Motion API. Framer Motion is an open source, production-ready library that's designed for creating creative animations. In order to support users who have enabled their device’s Reduced Motion setting and make accessible animations I used useReducedMotion hook. Based on whether useReducedMotion returns true or not we're passing different values to animate. That replace position transitions with opacity. Read More(1). Read More(2)
  • Handle 404 routes in React Router and provide a fallback component for displaying an imfamous 404 Page Not Found error to the user. Try to enter a page that doesn't exist - like 'invoice-tediko.netlify.app/gotcha'

You can find more about the things I used in the project in the README on github. I just wanted to point out most important things here.

Questions:

  1. As I am changing the theme and many colors are changing, I wasn't sure how to make the color system. I end up with object for dark/light theme with colors of each element and a few colors that are common. How would you approach that?
  2. I didn't want to create a special component for my headings since they have no logic. I created helper utility called typographyStyles where I put all styles that I use across application. Not sure about that tho.
  3. I am curious what method you use to name your components. I personally stick to option #2 because it has the most pros for me and a little longer import doesn't bother me.

Bugs:

  1. Clicking twice quickly on header logo (navigate to home page, which render Invoices component) causes component not to render. I am convinced that this is related to Framer Motion and AnimatePresence that allows components to animate out when they're removed from the React tree. I think build in isPresent state when clicking twice quickly didn't change the state. I overcame this problem with simple event.preventDefault() with a setTimeout function but..

Additional feedback or a criticism will be appreciated Thanks! 😁!

Code
Select a file

Please log in to post a comment

Log in with GitHub

Community feedback

  • Alex Kim•1,325
    @alex-kim-dev
    Posted over 3 years ago

    Awesome job, Tediko! I see you put a lot of effort into this project. I like that everything is well organized, files, code, commits, it's really easy to navigate through and find out how things are connected to each other. And great job on writing readme! Here is some feedback:

    • animation feels slow, I would adjust duration to be around 200-300 ms
    • accessing local storage might throw errors in some cases, for example if a user turned off all cookies in Chrome, some older browsers might throw even if only third-party cookies are blocked. So It's a good practice to wrap it in a try-catch block
    • there are a few places with a lot of nested if-else statements, like in formValidation.js. That's increasing cyclomatic complexity and makes code hard to understand, especially for people not familiar with the codebase. Try to avoid nesting conditions. Ideally it should look like this:
    () => {
      if (conditionA) return value1;
      // the following code will be executed only if(!conditionA)
      if (conditionB) return value2;
      // the following code will be executed only if(!conditionA && !conditionB)
      return value4;
    }
    
    • would be nice to work a bit on loading performance. I had DOMContentLoaded: 1.99s on fast connection and 5.32s on simulated "fast 3G".

    Good luck and until the next awesome project!

    Marked as helpful
  • Matt Studdert•13,611
    @mattstuddert
    Posted over 3 years ago

    Another awesome solution, tediko. Nice work!! 👍

    It's so clear you pay close attention to the details, and your write-ups are extremely helpful for others to read through. To answer your questions:

    • Using an object inside your theme.js file is fine and is typically the way this would be done using Styled Components. You can still use CSS variables if you prefer, though. One thing I would say is that you could use broader colour names. At the moment, you're duplicating a lot of the colour values. We use names like primaryBlue, accentGreen, etc., in our code.
    • Different people will have different approaches to this. We have a single Heading/index.js file that handles all possible heading styles. I'll send you the code for that file in Slack so you can take a look. It might give you some ideas about alternative approaches.
    • As you can see from above, we use the index.js pattern. We'd also have the Storybook stories and tests in the main component folder, e.g. /Heading. We like that using index.js saves a few characters here and there 😅

    I hope this helps! Keep up the awesome work! 🚀

    Marked as helpful
  • Harmanjot Singh•985
    @arkharman12
    Posted over 3 years ago

    Great work!!! I was kinda surprised by the amount of commits in the repo. Do you like to commit every change you make?

Join our Discord community

Join thousands of Frontend Mentor community members taking the challenges, sharing resources, helping each other, and chatting about all things front-end!

Join our Discord
Frontend Mentor logo

Stay up to datewith new challenges, featured solutions, selected articles, and our latest news

Frontend Mentor

  • Unlock Pro
  • Contact us
  • FAQs
  • Become a partner

Explore

  • Learning paths
  • Challenges
  • Solutions
  • Articles

Community

  • Discord
  • Guidelines

For companies

  • Hire developers
  • Train developers
© Frontend Mentor 2019 - 2025
  • Terms
  • Cookie Policy
  • Privacy Policy
  • License

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

How does the accessibility report work?

When a solution is submitted, we use axe-core to run an automated audit of your code.

This picks out common accessibility issues like not using semantic HTML and not having proper heading hierarchies, among others.

This automated audit is fairly surface level, so we encourage to you review the project and code in more detail with accessibility best practices in mind.

How does the CSS report work?

When a solution is submitted, we use stylelint to run an automated check on the CSS code.

We've added some of our own linting rules based on recommended best practices. These rules are prefixed with frontend-mentor/ which you'll see at the top of each issue in the report.

The report will audit 1st-party linked stylesheets, and styles within <style> tags.

How does the HTML validation report work?

When a solution is submitted, we use html-validate to run an automated check on the HTML code.

The report picks out common HTML issues such as not using headings within section elements and incorrect nesting of elements, among others.

Note that the report can pick up “invalid” attributes, which some frameworks automatically add to the HTML. These attributes are crucial for how the frameworks function, although they’re technically not valid HTML. As such, some projects can show up with many HTML validation errors, which are benign and are a necessary part of the framework.

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Frontend Mentor for Teams

Frontend Mentor for Teams helps companies and schools onboard and train developers through project-based learning. Our industry-standard projects give developers hands-on experience tackling real coding problems, helping them master their craft.

If you work in a company or are a student in a coding school, feel free to share Frontend Mentor for Teams with your manager or instructor, as they may use it to help with your coding education.

Learn more

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub

Oops! 😬

You need to be logged in before you can do that.

Log in with GitHub