From 9cf6bb90f356b5a52078a9d252fc1bda599535f8 Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Wed, 13 Mar 2024 23:47:32 +0900
Subject: [PATCH 1/8] chore: update tsconfig.json to prevent any

---
 tsconfig.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tsconfig.json b/tsconfig.json
index 6defef5..b5f80e8 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -9,7 +9,7 @@
     "allowSyntheticDefaultImports": true,
     "strict": true,
     "forceConsistentCasingInFileNames": true,
-    "noImplicitAny": false,
+    "noImplicitAny": true,
     "noFallthroughCasesInSwitch": true,
     "module": "CommonJS",
     "moduleResolution": "node",

From 3c9b38b579ff87198fcd50596e69520a1edb7801 Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Wed, 13 Mar 2024 23:52:09 +0900
Subject: [PATCH 2/8] chore: add @types/qs and @types/react-dom dependencies

---
 package.json |  2 ++
 yarn.lock    | 12 ++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/package.json b/package.json
index 9df29f6..0fb6ee2 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,8 @@
   },
   "devDependencies": {
     "@types/node": "^20.4.5",
+    "@types/qs": "^6.9.12",
+    "@types/react-dom": "^18.2.22",
     "@types/react-slick": "^0.23.10",
     "@typescript-eslint/eslint-plugin": "^6.2.0",
     "@typescript-eslint/parser": "^6.2.0",
diff --git a/yarn.lock b/yarn.lock
index e15b842..b4e27df 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -517,6 +517,18 @@
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
   integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
 
+"@types/qs@^6.9.12":
+  version "6.9.12"
+  resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.12.tgz#afa96b383a3a6fdc859453a1892d41b607fc7756"
+  integrity sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==
+
+"@types/react-dom@^18.2.22":
+  version "18.2.22"
+  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.22.tgz#d332febf0815403de6da8a97e5fe282cbe609bae"
+  integrity sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==
+  dependencies:
+    "@types/react" "*"
+
 "@types/react-redux@^7.1.20":
   version "7.1.25"
   resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.25.tgz#de841631205b24f9dfb4967dd4a7901e048f9a88"

From 09569bb90b4f43724562c2565ce7938f41ee8dca Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Wed, 13 Mar 2024 23:52:50 +0900
Subject: [PATCH 3/8] feat: add useTranslatedString hook

---
 src/hooks/useTranslatedString.tsx | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 src/hooks/useTranslatedString.tsx

diff --git a/src/hooks/useTranslatedString.tsx b/src/hooks/useTranslatedString.tsx
new file mode 100644
index 0000000..ed1a44b
--- /dev/null
+++ b/src/hooks/useTranslatedString.tsx
@@ -0,0 +1,11 @@
+import { useTranslation } from 'react-i18next';
+
+export const useTranslatedString = () => {
+  const { i18n } = useTranslation();
+
+  return <T,>(obj: T, key: keyof T extends string ? keyof T : never) => {
+    const translatedValue = obj[(i18n.language.startsWith('ko') ? key : `${key}_en`) as keyof T];
+
+    return typeof translatedValue === 'string' ? translatedValue : null;
+  };
+};

From 6738c729e192fb824671bfb7946898540c930923 Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Thu, 14 Mar 2024 00:25:09 +0900
Subject: [PATCH 4/8] migrate: @/index.tsx

---
 index.html                   |  2 +-
 src/{index.jsx => index.tsx} | 27 ++++++++++++++++++++++++---
 2 files changed, 25 insertions(+), 4 deletions(-)
 rename src/{index.jsx => index.tsx} (81%)

diff --git a/index.html b/index.html
index 35046ce..a589c03 100644
--- a/index.html
+++ b/index.html
@@ -42,7 +42,7 @@
     <noscript> You need to enable JavaScript to run this app. </noscript>
     <div id="root"></div>
     <div id="popup-root"></div>
-    <script type="module" src="/src/index.jsx"></script>
+    <script type="module" src="/src/index.tsx"></script>
     <!--
       This HTML file is a template.
       If you open it directly in the browser, you will see an empty page.
diff --git a/src/index.jsx b/src/index.tsx
similarity index 81%
rename from src/index.jsx
rename to src/index.tsx
index f68f03c..815c240 100644
--- a/src/index.jsx
+++ b/src/index.tsx
@@ -34,7 +34,9 @@ i18n
       formatSeparator: ',',
       format: (value, formatting, lng) => {
         if (value instanceof Date) {
-          return moment(value).locale(lng).format(formatting);
+          return moment(value)
+            .locale(lng ?? '')
+            .format(formatting);
         }
         return value.toString();
       },
@@ -42,6 +44,19 @@ i18n
   });
 
 import axios from 'axios';
+
+declare module 'axios' {
+  export interface AxiosRequestConfig {
+    metadata: {
+      gaCategory: string;
+      gaVariable: string;
+      startTime?: Date;
+      endTime?: Date;
+      duration?: number;
+    };
+  }
+}
+
 import Qs from 'qs';
 import { API_URL } from './const';
 
@@ -71,7 +86,8 @@ axios.interceptors.response.use(
   (response) => {
     response.config.metadata.endTime = new Date();
     response.config.metadata.duration =
-      response.config.metadata.endTime - response.config.metadata.startTime;
+      response.config.metadata.endTime.getTime() - response.config.metadata.startTime!.getTime();
+
     return response;
   },
   (error) => {
@@ -87,7 +103,12 @@ import React from 'react';
 import ReactDOM from 'react-dom/client';
 import App from './App';
 
-const container = document.getElementById('root');
+const container: HTMLElement | null = document.getElementById('root');
+
+if (!container) {
+  throw new Error('There must be root element');
+}
+
 const root = ReactDOM.createRoot(container); // createRoot(container!) if you use TypeScript
 root.render(
   <BrowserRouter>

From 0c6877168d70f6bd4325794ca6ec73869676bbcf Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Thu, 14 Mar 2024 00:29:25 +0900
Subject: [PATCH 5/8] docs: add docstring for useTranslatedString hook

---
 src/hooks/useTranslatedString.tsx | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/hooks/useTranslatedString.tsx b/src/hooks/useTranslatedString.tsx
index ed1a44b..5c2b45e 100644
--- a/src/hooks/useTranslatedString.tsx
+++ b/src/hooks/useTranslatedString.tsx
@@ -1,5 +1,12 @@
 import { useTranslation } from 'react-i18next';
 
+/**
+ * Custom hook that returns a function for translating strings based on the current language.
+ *
+ * @returns {function} A function that takes an object and a key and returns the translated string.
+ * @example const translate = useTranslatedString();
+ *          const translatedString = translate(review.lecture, 'title');
+ */
 export const useTranslatedString = () => {
   const { i18n } = useTranslation();
 

From ab47583a08715530db06e565bf3082edba636af5 Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Sun, 17 Mar 2024 18:34:49 +0900
Subject: [PATCH 6/8] g11n: default to Korean for undefined language settings

---
 src/index.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/index.tsx b/src/index.tsx
index 815c240..13bdddb 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -35,7 +35,7 @@ i18n
       format: (value, formatting, lng) => {
         if (value instanceof Date) {
           return moment(value)
-            .locale(lng ?? '')
+            .locale(lng ?? 'ko')
             .format(formatting);
         }
         return value.toString();

From 763fdfbf020dbf0fc650bffb8cbc14895f7dc2cf Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Sun, 17 Mar 2024 18:44:07 +0900
Subject: [PATCH 7/8] chore: remove unnecessary lines

---
 src/index.tsx | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/index.tsx b/src/index.tsx
index 13bdddb..48bbddc 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -87,7 +87,6 @@ axios.interceptors.response.use(
     response.config.metadata.endTime = new Date();
     response.config.metadata.duration =
       response.config.metadata.endTime.getTime() - response.config.metadata.startTime!.getTime();
-
     return response;
   },
   (error) => {
@@ -99,7 +98,6 @@ axios.interceptors.response.use(
 );
 
 import { BrowserRouter } from 'react-router-dom';
-import React from 'react';
 import ReactDOM from 'react-dom/client';
 import App from './App';
 

From 3d2c6f5d0276c240b1b36bc7a781e99b74fe4422 Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Sun, 17 Mar 2024 18:46:11 +0900
Subject: [PATCH 8/8] chore: remove redundant type annotation

---
 src/index.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/index.tsx b/src/index.tsx
index 48bbddc..afc2e9a 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -101,7 +101,7 @@ import { BrowserRouter } from 'react-router-dom';
 import ReactDOM from 'react-dom/client';
 import App from './App';
 
-const container: HTMLElement | null = document.getElementById('root');
+const container = document.getElementById('root');
 
 if (!container) {
   throw new Error('There must be root element');