1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】JISOU 課題4 デジタル名刺アプリを完成させた上での苦労と気づき

Last updated at Posted at 2025-02-02

はじめに

お疲れ様です、りつです。

React×TypeScriptで実装していたデジタル名刺アプリが完成いたしました。

今回は、作成したアプリのご紹介、および完成に至るまでの苦労や学びを共有できればと思います。

ご参考までに、以下が歴代の課題の記事です。

🎨 成果物について

オンライン上でユーザーが名詞を登録・閲覧できるアプリを作成しました。

アプリURL

GitHubリポジトリ

画面一覧

No 画面名 機能
1 TOP画面 名刺の検索
2 名刺登録画面 名刺の登録(バリデーションあり)
3 名刺閲覧画面 名刺の閲覧

画面の画像

TOP画面 名刺登録画面 名刺閲覧画面
image.png image.png image.png

使用技術

  • Vite
  • Chakra UI
  • React
  • React Hook Form
  • TypeScript
  • Jest / Testing Library (テスト)
  • Supabase (DB)
  • Firebase (ホスティング)
  • GitHub Actions (CI/CD)
  • React Router

⤴️ 以前と比べてみて

前回までと異なる部分として、以下の3点があげられます。

  1. React Routerを用いたページ遷移
  2. Supabase上で多対多のテーブル構造を利用
  3. データ削除バッチの実装と、GitHubActionsによる日次実行

1. React Routerを用いたページ遷移

以前作成した学習記録アプリは、1画面でCRUD(データの登録・表示・編集、削除)が行えましたが、今回実装したデジタル名刺アプリでは画面が3つ存在します。

そのため、各画面はReact Routerを用いて遷移するように実装しました。

2. Supabase上で多対多のテーブル構造を利用

デジタル名刺アプリでは、名刺登録時にマルチセレクトで「好きな技術」を複数選択できるように実装しています。

レコーディング-2025-02-02-134921.gif

名刺を表示する際には、登録した「好きな技術」はカンマ区切りで表示されます。

image.png

マルチセレクトの実装にあたり、Supabase上では以下のように3つのテーブルを用意し、user_skillテーブルを中間テーブルとして利用することで、1ユーザーに対して複数の好きな技術を登録、表示を行えるようにしました。

テーブル名 用途
users 名刺に登録されたユーザー情報の管理
skills 名刺登録時に「好きな技術」欄に表示するためのデータを管理
user_skill ユーザーと、そのユーザーが選択したスキルを管理する中間テーブル

3. データ削除バッチの実装と、GitHubActionsによる日次実行

今回Reactで初めてバッチ処理を実装しました。

具体的には、前日作成した名刺データ(usersuser_skillデータ)を削除するバッチを実装し、そのバッチを日本時間のAM6:00に実行するようにGitHubActionsに設定しました。

💡 苦労や気づき

  1. Supabaseの多対多の設定
  2. フォームのマルチセレクト
  3. 削除対象抽出時のタイムゾーンの差異の調整

1. Supabaseの多対多の設定

今回初めてSupabaseで多対多のテーブル構成を採用したのですが、実装時にリレーション先のデータがうまく取得できず、時間がかかってしまいました。

最終的には以下の記事に記載の内容で設定したところ、無事リレーション先データを取得することができるようになりました。

2. フォームのマルチセレクト

名刺登録時に、「好きな技術」欄で複数のスキル(例えばReactであったり、TypeScriptであったり)を選択できるようにしています。

マルチセレクト自体はChakra UIで簡単に表示はできるのですが、React Hook Formと組み合わせた際に、複数選択された値をテーブルに登録する際の方法などがわからなかったので調べながら実装を進めました。

また、マルチセレクトのテスト実装も初めてでしたが、以前までのテストの応用で実装できました。

React Testing Libraryは画面上の操作を模した書き方ができるので、テストコードの実装時はもちろん、テストコードを読む際もわかりやすいことが改めてメリットとして感じました。

3. 削除対象抽出時のタイムゾーンの差異の調整

日次バッチでは、朝の6時に前日分のデータ削除を行う必要があります。

しかし、Supabaseの日時カラムのタイムゾーンがUTCのため、登録した日本時間と、実際にテーブルカラムに登録される時間が9時間分ズレてしまうことにより、削除時に意図しないデータが削除されてしまう問題が発生しました。

例えば、1月3日の朝6時にバッチが起動する際、下表の4件のデータのうち、1~3が削除対象とならなければいけませんが、以下のSQLを実行すると、実際に削除されるのは2~4のデータとなります。

DELETE FROM public.users
    WHERE created_at >= (date_trunc('day', now()) - interval '1 day')
    AND created_at < date_trunc('day', now());
No データ登録を行った日時 Supabaseに登録された値 1月3日のバッチで削除されるべきデータか  SQLによって削除対象とされるか否か
1 1/2 8:59:59 1/1 23:59:59 ×
2 1/2 9:00:00 1/2 0:00:00
3 1/2 23:59:59 1/2 14:59:59
4 1/3 8:59:59 1/2 23:59:59 ×

今回は、SQLで条件を指定する際にタイムゾーンを指定してあげることで、想定されるデータを削除することが可能となりました。

タイムゾーンの部分はなかなか難しいところですが、SupabaseではタイムゾーンはデフォルトのUTCのままにしておくことが強く推奨されているようなので、上記のようにSQLの方の調整で対応することにしました。

Managing timezones
Every Supabase database is set to UTC timezone by default. We strongly recommend keeping it this way, even if your users are in a different location.
This is because it makes it much easier to calculate differences between timezones if you adopt the mental model that "everything in my database is in UTC time."

日時で条件を絞り込んだり、画面に日時を表示させるときなどはタイムゾーンによる時間のずれを考慮していく必要があります。

おわりに

前回と比べて実装自体は比較的スムーズに進められたように思いますが、新しい機能を取り入れるとそれなりにエラーや設定でハマってしまいますね。

繰り返しアプリ実装を繰り返すことで、少しずつ環境構築~実装~CI/CDにも慣れてきたことを実感しています。

次回の課題では、自分で考えたオリジナルアプリを実装していきます!

おそらく今まで以上に躓くことも多くなりそうですが、ここまで頑張ってきた集大成となりますので、完成まで頑張っていきたいと思います!

参考

JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてくださ!
▼▼▼

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?