88
65

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

めちゃめちゃ便利な日程調整ツール(以下の日程でご都合いかがでしょうかメーカー)をT3 Stackを使って作った話

Posted at

はじめに

少しキャッチーなタイトルにしました。すみません。

今回は、T3 Stack を使用して、そこそこ便利な日程調整ツール(以下日程でご都合いかがでしょうかメーカー)を作成した方法について解説します。

Google カレンダーと連携した「以下の日程でご都合いかがでしょうかメーカー」になります。

プロダクトの名前は、UnScheduleです。

Google カレンダーと連携した「以下の日程でご都合いかがでしょうかメーカー」の挙動について

最初に、Google カレンダーと連携した「以下の日程でご都合いかがでしょうかメーカー」であるUnScheduleの挙動について解説します。

使い方は非常にシンプルで、Google ログインを行った後に、カレンダーの期間を選択するだけです。

自動的にカレンダーの空いている時間を提案する、『以下の日程でご都合いかがでしょうか』の文章を作成してくれます。

Videotogif.gif

就業時間の設定や、休日の設定等を行うことが出来ます。

上記の動作で出来上がった文章が以下になります。

以下の日程でご都合いかがでしょうか。
10月21日(月)09:00〜12:00, 13:00〜13:30, 14:00〜17:00
10月22日(火)09:00〜10:30, 11:30〜12:30, 13:00〜16:00
10月23日(水)09:00〜10:00, 11:45〜12:30, 13:00〜17:00
10月24日(木)09:00〜12:30, 13:00〜13:30, 15:15〜17:00

作成した経緯

社内メンバーとの話し合いで、「日程調整って、基本的にはGoogleカレンダーの空いている時間を提案しているだけだよね」という話題が出たため、とりあえず試しに作ってみることにしました。

以前、エンジニア向けのタイピングゲームを作成した際に、社内用に作成したT3 Stackのテンプレートがあったため、今回はそれをそのまま流用してプロダクトを作成しました。

技術スタック

T3 Stack の構成で作成しました。

  • Next.js
  • TypeScript
  • tRPC
  • Prisma
  • TailwindCSS
  • Auth.js
    という構成ですね。

データベースには Supabase を使用し、デプロイ先は Vercel に設定しています。今回のプロジェクトでは、Next.js の App Router を採用しました。

開発した機能について

以下に、今回のプロダクト(Google カレンダーと連携した「以下の日程でご都合いかがでしょうかメーカー」)を作成する際に開発した機能についてまとめていきます。

Google ログイン機能

Google のログイン機能を作成しました。

image.png

フロントの認証情報の管理は、NextAuth.js に任せています

adapterPrismaAdapterを設定することで、認証情報のデータを Prisma を介して丸っとデータベース(今回は Supabaseを利用しています)に格納しています。

adapter: PrismaAdapter(db) as Adapter

Google カレンダーの空いている時間帯を取得する機能

ユーザーが選択した期間における、Google カレンダーの空いている時間を取得する機能を作成しました。

以下のコードです。

const auth = new google.auth.OAuth2({
  clientId: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
});

const accountFromDb = await db.account.findFirst({
  where: { userId: ctx.session.user.id },
  select: { id: true, access_token: true, expires_at: true },
});

auth.setCredentials({
  access_token: accountFromDb?.access_token,
});

const calendar = google.calendar({ version: 'v3', auth: auth });

const timeZone = (await calendar.settings.get({ setting: 'timezone' })).data.value;

const response = await calendar.freebusy.query({
  requestBody: {
    timeMin: startDate,
    timeMax: endDate,
    items: [{ id: 'primary' }],
    timeZone,
  },
});

こちらのコードで、Google カレンダーの空いている時間を取得しました。

上記のコードについて、ざっくりと解説します。

1. OAuth2を使った認証の設定

const auth = new google.auth.OAuth2({
  clientId: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
});

ここでは、GoogleのOAuth2クライアントを初期化しています。環境変数に保存されたクライアントIDとクライアントシークレットを使って、GoogleのAPIにアクセスするための認証情報を設定します。

2. データベースからアクセストークンを取得

const accountFromDb = await db.account.findFirst({
  where: { userId: ctx.session.user.id },
  select: { id: true, access_token: true, expires_at: true },
});

次に、データベースから、現在ログインしているユーザーのアクセストークンとその期限を取得しています。このトークンは、Google Calendar APIに対してリクエストを行うために必要なものです。

3. アクセストークンの設定

auth.setCredentials({
  access_token: accountFromDb?.access_token,
});

ここで、取得したアクセストークンをOAuth2クライアントに設定します。これにより、Google Calendar APIに対して認証されたリクエストが行えるようになります。

4. Google Calendar APIクライアントの初期化

const calendar = google.calendar({ version: 'v3', auth: auth });

Google Calendar APIのクライアントを作成しています。このクライアントを使って、カレンダーに関する操作(例: 空き時間の確認など)を行うことができます。

5. ユーザーのタイムゾーンを取得

const timeZone = (await calendar.settings.get({ setting: 'timezone' })).data.value;

Google Calendar APIの設定を利用して、ユーザーのタイムゾーン情報を取得します。この情報は、後のクエリで適切な時間を扱うために使います。

6. 空き時間のクエリ

const response = await calendar.freebusy.query({
  requestBody: {
    timeMin: startDate,
    timeMax: endDate,
    items: [{ id: 'primary' }],
    timeZone,
  },
});

この部分では、Google Calendar APIのfreebusy.queryを使って、指定された期間(startDateendDate)のユーザーの空き時間を問い合わせます。itemsprimaryを指定しているため、ユーザーのメインカレンダーが対象になります。タイムゾーン情報も含めてリクエストを行い、結果がresponseに返されます。

悩んだこと

Supabaseのスペックを抑えたのが原因か、tRPCの利用が影響しているのかは不明ですが、APIのレスポンスがかなり遅いです。

また、Google カレンダーの データを取得する API も、若干遅いです。

そのため、日程を選択した後に 3 秒ほど待たされることになります。

待ち時間を短縮するため、ページ読み込み時にあらかじめ1ヶ月分のカレンダーデータを取得するように修正しました。その結果、日程調整のテキストが爆速で生成されるようになりました。

削った機能

複数の期間を選択する機能は削除しました。最終的には日程調整用のテキストが生成されるだけなので、不要な部分は手動で消す方が、ユーザー体験が向上すると判断したためです。

また、特定の時間(昼休みなど)を除外する機能も検討しましたが、実装は見送りました。Google カレンダーにその時間を予定として入れてもらう方がシンプルで、ユーザーにもわかりやすいと考えたからです。

終わりに

今回は、Google カレンダーと「以下の日程でご都合いかがでしょうかメーカー」である、UnScheduleの技術スタックと実装について紹介しました。

是非、一度使用して頂ければと思います。

お疲れさまでした。

88
65
2

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
88
65

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?