Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found

Submitted

REST Countries API with color theme switcher

#react

@catherineisonline

Desktop design screenshot for the REST Countries API with color theme switcher coding challenge

This is a solution for...

  • HTML
  • CSS
  • JS
  • API
4advanced
View challenge

Design comparison


SolutionDesign

Solution retrospective


Hello, Frontend Mentor community! This is my solution to the REST Countries API with a color theme switcher.

I appreciate all the feedback you left that helped me to improve this project. I fixed the issues I had previously and added new features per your recommendation.

I have done this project a while ago however if you are here and have any feedback, tips, or ideas to share, I will be more than glad to hear them out!

Thanks

Community feedback

@fadelun

Posted

i have seen your website, but when dark mode some color it doesn't change. maybe you can check on style.css, there is ".region-list option"

Marked as helpful

1

Travolgi 🍕 31,500

@denielden

Posted

Hey Catherine, congratulations on completing the challenge! You did a great job 😉

Let me give you some little tips for optimizing your code:

  • add header tag ad wrap the nav to improve the Accessibility
  • with main tag wrap the content of page
  • add descriptive text in the alt attribute of the images
  • remove all unnecessary code, the less you write the better as well as being clearer: for example the div container of flag images and styling directly the img element
  • use ul element for the details text of country instead of multiple p
  • if you want to use the title for the href attribute you have to parse it in url, it can give problems creating links with empty spaces or special characters
  • if I type a query that doesn't give any results, nothing happens, try adding a "no results" message
  • I would also add a query reset button, I find it very convenient
  • in the filters there is no way to return to all countries after choosing a region, add an entry "all region"
  • in the region filter after clicking on a region the submenu does not close
  • instead of using px use relative units of measurement like rem -> read here
  • to fetch data from API create and use a custom hook so you can reuse the same code in many different components and keep the logic separate from the design

Hope this help! Happy coding 😁

Marked as helpful

1

P

@christopher-adolphe

Posted

Hi @catherineisonline,

You did a great job in completing this challenge using React. 👍

  • For your issue to display the border countries, I suggest you build a list of countries with their respective alpha codes on the initial load since you are already fetching all the countries. Something like this:
const countryCodes: [
  {
    name: 'Albania',
    alpha2Code: 'AL',
    alpha3Code: 'ALB'
  },
  {
    name: 'Algeria',
    alpha2Code: 'DZ',
    alpha3Code: 'DZA'
  }
]

Then you could store this list in a global state using React's context API and when a user goes to the country page you can find the country codes from this countryCodes list and map them to their respective full name.

  • It might also be a good thing to wrap asynchronous logics in a try...catch block to catch any potential errors.

I hope this helps.

Keep it up.

Marked as helpful

1

P

@christopher-adolphe

Posted

Hi @catherineisonline, 👋

I'm happy to help and glad to see that this was helpful to you. 👍

I don't know if you had the chance to give it a try but here's what I had in mind when suggesting this.

  • Create a new context directory under your src directory
  • Create a CountriesContext.js file inside this new directory with the following content:
import { createContext, useState } from  'react';

// Creating a context which will be accessible to
// the components of the React app. Here the context
// is an object with 2 keys; `onBuildCountryCodes` and
// `onGetCountryNames`, which are functions to build the
// country codes list and to get the country names list
const CountriesContext = createContext({
  onBuildCountryCodes: (countries) => {},
  onGetCountryNames: (borders) => {}
});

// This `CountriesContextProvider` will be use as a
// wrapper component to provide the context to the
// entire React app
export function CountriesContextProvider({ children }) {
  const [ countryCodes, setCountryCodes ] = useState([]);
  
  // The `buildCountryCodesHandler` function contains the logic
  // to build the countryCodes list from a list of countries
  const buildCountryCodesHandler = (countries) => {
    countries.forEach(country => {
      const { name, alpha2Code, alpha3Code } = country;
      
      setCountryCodes(prevState => [
        ...prevState,
        { name, alpha2Code, alpha3Code }
      ]);
    });
  };
  
  // The `getCountryNamesHandler` function contains the logic
  // to return a list of country name from a list of country
  // border codes
  const getCountryNamesHandler = (borders) => {
    return countryCodes.map(country => borders.includes(country.alpha3Code) ? country.name : null);
  };
  
  // Defining a `contextValue` object that matches the structure
  // of the `CountriesContext` context and passing the handler
  // functions as value to it's keys. We will then pass it to the
  // `value` prop of the `<CountriesContext.Provider>` component
  const contextValue = {
    onBuildCountryCodes: buildCountryCodesHandler,
    onGetCountryNames: getCountryNamesHandler
  };

  return (
    <CountriesContext.Provider value={ contextValue }>
      { children }
    </CountriesContext.Provider>
  );
}

export default CountriesContext;
  • Wrap your root component inside index.js with the <CountriesContextProvider> component like this:
// all your other imports
import CountriesContextProvider from './context/CountriesContext';

root.render(
  <React.StrictMode>
    <CountriesContextProvider> {/* Wrapping starts here */}
      <BrowserRouter basename={process.env.PUBLIC_URL}>
        <div className="mainContainer">
          <Header />
            <Routes>
              <Route exact path="/:name" element={<Country />} />
              <Route path="*" element={<Error />} />
              <Route path="/" exact element={<Countries />} />
            </Routes>
          </div>
      </BrowserRouter>
    </CountriesContextProvider> {/* Wrapping ends here */}
  </React.StrictMode>
);
  • You can now access this context in your <Countries /> component using the useContext hook like this:
import { useState, useEffect, useContext } from 'react';
import { CountriesContext } from '../context/CountriesContext';

export default function Countries()  {
  // ...
  // Getting the `onBuildCountryCodes` function from the context
  const { onBuildCountryCodes } = useContext(CountriesContext);

  const fetchCountries = async () => {
    try {
      setIsLoading(true);
      const response = await fetch(url);
      const data = await response.json();
      setCountries(data);
      // Passing the list of countries fetched from the API to
      // the `onBuildCountryCodes` function to build the `countryCodes` list
      onBuildCountryCodes(data);
    } catch (error) {
      console.log(error);
    } finally {
      setIsLoading(false);
    }
  };

  // ...
}
  • Then access the context in your <Country /> component to get the names of the border countries like this:
import { useState, useEffect, useContext } from 'react';
import { CountriesContext } from  '../context/CountriesContext';

export default function Country()  {
  // ...
  const [borderGroup, setCountryBorders] = useState([]);

  // Getting the `onGetCountryNames` function from the context
  const { onGetCountryNames } = useContext(CountriesContext);
  
  useEffect(() => {
    const fetchCountryData = async () => {
      try {
        setIsLoading(true);
        const url = `https://restcountries.com/v2/name/${name}`;
        const response = await fetch(url);
        const data = await response.json();
        setCountry(data);
        // Passing the borders list to the `onGetCountryNames` function to
        // get the full name of the border countries and using `setCountryBorders`
        // to set the `borderGroup` state
        setCountryBorders(onGetCountryNames(data[0].borders));
      } catch (error) {
        console.log(error);
      } finally {
        setIsLoading(false);
      }
    };
    
    fetchCountryData();
  }, [name, borderGroup]);
  
  // ...
}

Let me know if that worked for you.

Sorry, 😔 this markdown editor doesn't render comments in code snippets nicely. Maybe you could paste them in your code editor for better readability. 🙂

Best regards.

0
Adarsh 1,560

@adram3l3ch

Posted

Hi Catherine you did a great job :) . You can sort out the border issue by making the border as a component itself and fetch about that country on that component. Also the problem of github pages with SPAs can be solved by using something like

(function(l) {
        if (l.search[1] === '/' ) {
          var decoded = l.search.slice(1).split('&').map(function(s) { 
            return s.replace(/~and~/g, '&')
          }).join('?');
          window.history.replaceState(null, null,
              l.pathname.slice(0, -1) + decoded + l.hash
          );
        }
      }(window.location))

You can refer about the same here

Marked as helpful

1

@Javieer57

Posted

Hi!

I found a bug in the neighboring countries' tags. When you click on one, it adds the neighboring countries of the current one to the neighboring countries from the previous screen. Excellent job! :)

1

@catherineisonline

Posted

@Javieer57 Hi, thanks for the feedback. I have fixed this issue and it should be working properly now. Thank you

0
Kiyoomi 480

@Jukiyoomi

Posted

I think you can get data of a country using its code with this link https://restcountries.com/v3.1/alpha/{code} from the api.

1

qadzek 420

@qadzek

Posted

Nice work. I like how you have implemented the "Filter by Region" menu.

A couple of small remarks:

  • I can confirm the bug described by @Javieer57.
  • The use of any in TS is discouraged.
  • There are tools online to automatically convert a JSON response to TS types: https://app.quicktype.io
  • I don't think there is a need for separate FilteredCountries and AllCountries components.
  • A single API call should suffice.
0

@catherineisonline

Posted

@qadzek I have fixed this issue with borders and it should be working properly now. Thanks for the feedback I will get back to the other suggestions later on

0
Abdul 8,560

@Samadeen

Posted

Hello Catherine... You did beautifully well on this project, can you kindly recommend resources to learn React

0

@catherineisonline

Posted

@Samadeen Hi, thanks! I started learning by practicing and never really read docs, so if you understand JavaScript it makes React much easier. I started reading much later to understand some concepts better but the internet is full of useless information. I recommend starting with official docs: https://reactjs.org/docs/getting-started.html

It's not very hard to understand but if they have some topics not clear enough, you can google and try to find some more info.

0
Abdul 8,560

@Samadeen

Posted

@catherineisonline Thank you. I appreciate

0

@D3press3dd

Posted

wow, you've grown quite a bit in the area, keep it up, check out this tool for animations https://www.framer.com/motion/ you can see what you can do in my solution to this challenge, it is really intuitive you can check this video https://www.youtube.com/watch?v=u_95SPKE6vg and see how it works in just 5 minutes

0

@sparrowsl

Posted

This is just too amazing, makes me want to do it now. I have no words to say here :)

I only found that the spacing on the right side is not consistent with the left (on desktop) Everything else if just fire and amazing

0

@catherineisonline

Posted

@benjithorpe I will check it out, still have to finish off the mobile version. Thanks for the feedback!

1
Zein 300

@Zein-MB

Posted

Amazing! you're just an example of success!!

0

Valeri 190

@Valeri85

Posted

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'value') Search.js:21 e = e.value;

0

Please log in to post a comment

Log in with GitHub
Discord logo

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