Repository: freeCodeCamp/freeCodeCamp
File: client/src/redux/theme-saga.js (JavaScript)

Code before:
import { userThemeSelector } from './selectors';

function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initalizeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  const isUserThemeDark = (yield select(userThemeSelector)) === 'night';
  const isLocalStorageThemeDark = localStorage.getItem('theme') === 'dark';
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  /*
   The order of priority is localStorage > user > system
   That is why order matters in the logical expression below.
   Once the localStorage is set, it will always take precedence over the user and system theme.
   */

  const selectTheme =
    isLocalStorageThemeDark || isUserThemeDark || isSysThemeDark
      ? 'dark'
      : 'light';

  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initalizeThemeSaga)
  ];
}


Review comment (suggestion):
Sorry, Ahmad, I didn't ask the right question.

If order matters, we can't use `isLocalStorageThemeDark || isUserThemeDark || isSysThemeDark` because that's true if _any_ of the three are true and false otherwise. It doesn't encode the precedence.

Thing is, what exactly _is_ the precedence? If the localStorage has a theme, use it. Otherwise if there's a userTheme, use it. Otherwise default to system?

If that's the case this needs to do things like

```
const hasLocalStorageTheme = localStorage.getItem('theme') !== null;
if (hasLocalStorageTheme) return localStorage.getItem('theme') === 'dark' ? 'dark' : 'light'
// and the same for the other two.
```


Code after:
import { userThemeSelector } from './selectors';

function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initializeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  const userTheme = yield select(userThemeSelector);
  const localStorageTheme = localStorage.getItem('theme');
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  let selectTheme = 'light';

  if (localStorageTheme !== null) {
    selectTheme = localStorageTheme === 'dark' ? 'dark' : 'light';
  } else if (userTheme) {
    selectTheme = userTheme === 'night' ? 'dark' : 'light';
  } else if (isSysThemeDark) {
    selectTheme = 'dark';
  }

  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initializeThemeSaga)
  ];
}