Skip to content

Latest commit

 

History

56 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Imgur

Cine Wars: The Rise of Minsu

Cine Wars is a React app using SWAPI that lists characters from Star Wars series with Gaming UI.

Motivation

Even though this web app is a simple project with two view pages, I always thought that websites should have any interesting feature. Therefore I tried to add some storyline. 😄

Imagine, you are a high-grade person from the Galactic Empire, you are on board the Star Destroyer, and you are looking for someone's information. You asked your subordinate(Stormtrooper) to prepare the person database.

That is the main plot of this website and I added a dialogue box to make users be absorbed in having a conversation with Stormtrooper.

Tools

  • TypeScript

  • React.js with CRA

  • Functional Components with React Hooks

  • Redux, Redux-thunk

  • Custom style and layout with styled-component and react-grid-system

    I tried to not depend on design libraries like BootStrap or Material-UI. I prefer CSS-in-JS style component using styled-component or emotion.

  • TDD with testing-library(rtl)

  • Deployed to AWS S3 / Cloudfront / Route53 with a custom domain

Features

List Page

  • Display a list of characters
  • Each item should display the name, birth year, height, and mass
  • The list should use pagination
  • Each item should be clickable and bring you to the detail page

Character Page

  • Show all the properties of the character
  • Back button to the list page

Additional Features

  • Loading Indicator

    I made a custom loading indicator as an image of spinning Galactic Empire logo.

  • Consistency between list and detail page with global state management

    I managed a global state of a page number, character list of the page, and dialogue text with Redux to implement this. I prefer to use DUCKS pattern, but I am willing to learn more about other global state management style or libraries like MobX, Constate and Recoil.

  • Custom Header Logo Image / Favicon

  • Responsive and compatible with various browsers(Chrome, Safari, Edge, and Samsung Internet, however, Firefox has a minor issue.)

    4k might not compatible.

Imgur

  • Background Music Player (Galactic Empire Theme) / Star Destroyer

    I still can't forget the moment I first saw the scene that Star Destroyer appeared in "A New Hope". I tried to implement that feeling with the bgm. I enjoyed it a lot making this project 😊 and if you look at my Github username, you can see why I love space movies. ⭐

  • Added every character's portrait image and Lazy Loading with Skeleton

    SWAPI does not provide character's image, so I added image one by one and it took really long time. 😵

  • Different dialogue text by every character! It parses colors as well. See composeDialog()

Imgur

  • Testing code for view pages
  • Image optimization for performance

Issues

  • If data is too long in Character Detail View, layout goes a little bit wrong (See Kenobi's case)

    If I have additional time, I would spend time on that establishing layouts and Array.map() methods in consideration of this case.

  • iOS Safari audio player has a bug

    I guess it is due to Safari's policy related to user interaction.

  • When loader size is inherit by parents, it resizes viewport and occasionally makes scrolls.

    I guess it is due to diplay: flex and react-grid-system library.

  • In Firefox, the main list table is not centered.

Problem and solutions

  1. The fetched data doesn't have id column and I firstly thought using sequential index as a key but id: 17 data was missing. I decided to use 'url' column for the key by slice(), because every url has same front part. https://swapi.dev/api/people/[:id] I could use regex to parse the id, but slice() is a faster and easier option.

  2. Pagination was not that hard because server returned 10 characters list by each page. I just needed to store the page state. Pagination lock is implemented when page is equal to 1(the first page), < Prev button will be disabled, and when next fetching page is not existed and current list length of this page is less than 10, that is the last page, Next > button will be disabled.

  3. The character data was incomplete and has own children url to fetch again. I made a module to resolve the promises like this considering types of data. If I have additional time, I would add some error handling exceptions by server's response.

  4. To give gaming like user experience, I had to add Typewriter animation in the dialogue box. Firstly, I tried css animation: typing and failed. I guess due to display: flex, but couldn't make it. Secondly, I tried to keep updating the state by adding one character, it was difficult dealing with asynchronous functions. I ended up using the library 'react-typist'. I want to develop typewriter animation by myself if I have additional time.

  5. I wanted to make different dialogue text including colours by a character I considered how to implement this, the first approach was a bit wrong. (you can see here) I ended up making html tag string and convert to html tag. I could use dangerouslySetInnerHTML simply but I know it could occur XSS security problem(in case of big project), so I used the library 'react-html-parser'. It easily renders the component from html string.

  6. There is http network issue with fetch() in the testing code. It looks like could be solved by changing method from fetch() to axios() with an adapter option. However, in this project, I had to use fetch API.

    I used testing-library(rtl) for the first time, it feels like rtl usually focuses on the result of rendering. It would be useful to test from the perspective of the user. My testing code is beginner level, I know the importance of TDD and want to learn and practice more about it.

  7. CORS problem. Mixed Content: The page at 'https://mycloudfronturl.cloudfront.net/character/5' was loaded over HTTPS, but requested an insecure resource 'http://swapi.dev/api/people/5/'. This request has been blocked; the content must be served over HTTPS. There was a CORS error but I was sure that I did fetch request on https only by replace('http', 'https'). However, the fact is that the SWAPI is served at http and my cloudfront server is loaded on https, so the browser blocks the request. since I have no control over the api, I added meta tag <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">. It solves.

  8. If I spend additional time in terms of performance, I think I would add a caching feature because the character data is not changed very often in the database. Therefore if I accumulate the characters list data in Redux state additionally when a user navigates the page from 2 to 8(assuming 1 is already fetched), it would get rid of inefficient fetching when the user navigates pages back from 8 to 2 again.

Timeline 📅

  • 24 Mar - Boilerplate, basic fetch logic
  • 25 Mar - Redux, main fetch logic, design&layout
  • 26 Mar - Added bgm player, favicon, other design factors.
  • 27 Mar - TDD cases for view pages, bug fixes
  • 28 Mar - Deployment, documentation

About

Cine Wars is a React app that lists characters from Star Wars series with Gaming UI.

Resources

Stars

17 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages