Raycastで勤怠打刻ができるExtensionを開発してみた

## はじめに

みなさんは[Raycast](https://www.raycast.com/)利用していますか?ランチャーとしてアプリケーションを即座に開けることはもちろんですが、Raycast上のコマンドからアプリケーションの操作を実行できることも魅力だと思います。

そんなRaycastのExtensionをReactで開発できると知り、勤怠打刻用のExtensionを作成してみました。

弊社では勤怠打刻のツールに[HRMOS勤怠](https://hrmos.co/kintai/)を利用しているため、[HRMOS勤怠のAPI](https://ieyasu.co/docs/api.html)を利用します。

## 開発したコマンド

### 打刻履歴コマンド

打刻履歴コマンドでは、直近の打刻履歴をAPIから取得し、[List](https://developers.raycast.com/api-reference/user-interface/list?q=list)を使って表示させています。日付の部分は[List.Section](https://developers.raycast.com/api-reference/user-interface/list?q=list#list.section)というコンポーネントを利用しています。

![スクリーンショット 2022-12-07 0.54.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384849/8d47bcff-f546-509a-9770-bae8defe5f23.png)

### 打刻コマンド

打刻コマンドでは、プルダウンから「出勤」、「退勤」、「休憩開始」、「休憩終了」を選択し、```cmd + Enter```を入力することで該当した打刻を行うことができます。

![スクリーンショット 2022-12-07 1.01.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384849/2fc93a51-7736-1bf2-426b-457f1325909c.png)



## Extensionの開発におけるポイント

### package.jsonについて

作成したExtensionのメタ情報はpackage.jsonで管理します。[参考](https://developers.raycast.com/information/manifest#preference-properties)

### commands

commandsというプロパティでは、作成したそれぞれのコマンドに関する情報を管理します。その中のnameプロパティはファイル名と一致させる必要があります。例えば、nameプロパティをstampにした場合は、stamp.tsxやstamp.jsxというファイルをsrc配下に置く必要があります。フォルダ構成に関しては[こちら](https://developers.raycast.com/information/file-structure)に記載されています。コマンドのtitleなどをcreate extensionで作成した後にファイル名やnameを一致させないとエラーになりますので、注意してください。

``` json
"commands": [
    {
      "name": "stamp",
      "title": "stamp",
      "description": "HRMOSの打刻をします。",
      "mode": "view"
    },
    {
      "name": "stamp_logs",
      "title": "stamp logs",
      "description": "打刻の履歴を確認することができます。",
      "mode": "view"
    }
],
```

### preferences

package.json内のpreferencesプロパティではAPIキーのような環境に依存した情報を管理することができます。requiredプロパティをtrue
にすれば、指定のpreferenceがない場合にユーザーに対して画像のような画面から情報の入力をさせることができます。

``` json
"preferences": [
    {
      "name": "apiKey",
      "description": "HRMOSのAPI keyを入力してください。https://ieyasu.co/docs/api.html?_ga=2.219204185.1903119651.1667613637-717436112.1661213988#section/APIURL",
      "type": "password",
      "required": true,
      "title": "HRMOS API key",
      "placeholder": "HRMOSのAPI key"
    }
]
```

ちなみに、preferenceを再入力したい場合にはRaycastを起動し、検索バーからExtensionsを検索して、作成しているExtensionのところから削除することができます。

### useFetch

Raycastが提供するHooksに[useFetch](https://developers.raycast.com/utilities/react-hooks/usefetch)が存在します。useFetchはswrと似たような書き方で、リソースをfetchしたり状態の管理を行うことができます。下記のコードは1つ目のuseFetchでauthenticationTokenを取得しています。2つ目のuseFetchのようにexecuteプロパティがtrueになったタイミングで発火させるようなことも可能です。他にもonDataやonErrorのようなプロパティもあるので是非公式のドキュメントをご覧になってください。

``` tsx
  const { data: authenticationToken } = useFetch<AuthenticationToken>(
    API_ENDPOINT + "authentication/token",
    {
      headers: {
        Authorization: `Basic ${apiKey}`,
      },
    }
  );

  const { data: stamps } = useFetch<Array<StampItemProps>>(
    `${API_ENDPOINT}stamp_logs/user/${USER_ID}?limit=${STAMPS_LIMIT}`,
    {
      headers: {
        Authorization: `Token ${authenticationToken?.token}`,
      },
      execute: !!authenticationToken,
    }
  );
```

### Toast

APIとの通信が成功した時や例外処理が発生した時に、ユーザーへその内容を伝えたいときは、[Toast](https://developers.raycast.com/api-reference/feedback/toast)が使えます。

``` tsx
if (response.status === 200) {
  await showToast({ title: "打刻に成功しました" });
} else {
  await showToast({
    style: Toast.Style.Failure,
    title: "打刻に失敗しました",
    message: data.message,
  });
}
```

![スクリーンショット 2022-12-07 9.33.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384849/c9a86b34-dd9d-41d5-55dc-de3686359c0f.png)

![スクリーンショット 2022-12-07 2.06.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384849/af8e448e-b3df-423d-a806-6c088d1a8b83.png)

## 最後に

RaycastのExtensionの開発では、Reactで得た知識を活かすことができました。今後も、何か作成したいExtensionがあれば開発していきたいと思います！