Cloudscape Design System を導入した Next.js + Amplify アプリケーションの Top Navigation コンポーネントで Cognito からのサインアウトアクションを実装する

Cloudscape Design System を導入した Next.js + Amplify アプリケーションの Top Navigation コンポーネントで Cognito からのサインアウトアクションを実装する

Clock Icon2024.10.27

いわさです。

先日 Amplify で作成したアプリケーションの UI コンポーネントに Cloudscape Design System を使う機会がありました。(Cloudscape Design System の詳細は以下を)

https://dev.classmethod.jp/articles/try-cloudscape-design-system-with-next-js/

Cloudscape では様々なコンポーネントが用意されており、その中のひとつに Top Navigation というコンポーネントがあります。
サンプルでサインアウトのボタンが用意されていて良い感じだったのでそのまま遣いたかったのですが、Amplify のサインアウト機能を呼び出す時にちょっと悩んだので備忘録として実装の流れを残しておきたいと思います。

ベースのアプリケーションを作成する

まずはベースのアプリケーションを用意します。
React + Next.js でアプリケーションを新規作成し、そこに Amplify を追加します。
ここで一度サンドボックスをデプロイし、今回はサインアウトが関係しているので Authenticator を使ってサインイン出来るようにします。

https://ja.react.dev/learn/start-a-new-react-project

https://docs.amplify.aws/react/build-a-backend/auth/set-up-auth/

EFD75E9B-15FA-4C34-8E54-2ADFC80F6F92.png

その後 Cloudscape を追加してナビゲーションを実装します。
実装内容は次のコンポーネントのサンプルの通りで静的なものです。

https://cloudscape.design/get-started/integration/using-cloudscape-components/

https://cloudscape.design/components/top-navigation/

ここまでですぐに次のような形になると思います。

app/page.tsx
'use client'

import Image from "next/image";
import { Authenticator } from '@aws-amplify/ui-react';
import { Amplify } from 'aws-amplify';
import outputs from '@/amplify_outputs.json';
import '@aws-amplify/ui-react/styles.css';

import "@cloudscape-design/global-styles/index.css"
import TopNavigation from "@cloudscape-design/components/top-navigation";
import Button from "@cloudscape-design/components/button"

Amplify.configure(outputs);

export default function Home() {
  return (
    <Authenticator>
      {({ signOut, user }) => (
        <div>
          <TopNavigation
            identity={{
              href: "#",
              title: "Service",
            }}
            utilities={[
              {
                type: "button",
                text: "Link",
                href: "https://example.com/",
                external: true,
                externalIconAriaLabel: " (opens in a new tab)"
              },
              {
                type: "button",
                iconName: "notification",
                title: "Notifications",
                ariaLabel: "Notifications (unread)",
                badge: true,
                disableUtilityCollapse: false
              },
              {
                type: "menu-dropdown",
                iconName: "settings",
                ariaLabel: "Settings",
                title: "Settings",
                items: [
                  {
                    id: "settings-org",
                    text: "Organizational settings"
                  },
                  {
                    id: "settings-project",
                    text: "Project settings"
                  }
                ]
              },
              {
                type: "menu-dropdown",
                text: "Customer Name",
                description: "[email protected]",
                iconName: "user-profile",
                items: [
                  { id: "profile", text: "Profile" },
                  { id: "preferences", text: "Preferences" },
                  { id: "security", text: "Security" },
                  {
                    id: "support-group",
                    text: "Support",
                    items: [
                      {
                        id: "documentation",
                        text: "Documentation",
                        href: "#",
                        external: true,
                        externalIconAriaLabel:
                          " (opens in new tab)"
                      },
                      { id: "support", text: "Support" },
                      {
                        id: "feedback",
                        text: "Feedback",
                        href: "#",
                        external: true,
                        externalIconAriaLabel:
                          " (opens in new tab)"
                      }
                    ]
                  },
                  { id: "signout", text: "Sign out" }
                ]
              }
            ]}
          />
          <Button>aaa</Button>
        </div>
      )}
    </Authenticator>
  );
}

アプリケーションにサインインしたユーザーは、次のように Top Navigation が表示されます。
この時点ではまだナビゲーションメニューのサインアウトは機能しません。

676B54BC-9265-45D9-989D-B3253922F1E2.png

サインアウト機能を実装する

では、ナビゲーションメニューのこちらのサインアウト機能を実装していきましょう。

D9DCC254-93F5-46E7-A687-1852DEC8B69E.png

フロントの実装としては Top Navigation コンポーネントの utilities プロパティに menu-dropdown タイプのアイテムを設定しており、さらにその中で複数の項目を定義しているようです。

949EFFF6-AB34-4E92-8F23-0816AA412DE4.png

で、先程の Top Navation コンポーネントドキュメントを見てみると、API タブの中で menu-dropdown の onItemClick が使えそうなことが確認できました。これを使ってみましょう。

96C56EBE-50E9-429A-8545-4D7467BD7D77.png

上記の説明だと使えそうなことはわかったのですが、具体的な実装例があるとありがたいなぁと思っていると以下にその案内がありました。ありがてぇ。

https://github.com/cloudscape-design/components/discussions/604

これを応用し、さらに先日ブログを書いた Amplify サインアウト API を呼び出してみたいと思います。

https://dev.classmethod.jp/articles/amplify-sighout/

こんな感じで修正しました。
handleUtilityClickでどのメニューが押されたか判定して、サインアウトであれば Auth モジュールの sighOut API を実行します。

:

import { signOut } from "aws-amplify/auth"

Amplify.configure(outputs);

export default function Home() {
  const handleUtilityClick = async (e: CustomEvent) => {
    if (e.detail.id === 'signout') {
      await signOut();
    }
  };

  return (
    <Authenticator>
      {({ signOut, user }) => (
        <div>
          <TopNavigation
            identity={{
              href: "#",
              title: "Service",
            }}
            utilities={[

:

              {
                type: "menu-dropdown",
                text: "Customer Name",
                description: "[email protected]",
                iconName: "user-profile",
                onItemClick: handleUtilityClick,
                items: [
                  { id: "profile", text: "Profile" },
                  { id: "preferences", text: "Preferences" },

:

                  { id: "signout", text: "Sign out" }
                ]
              }
            ]}
          />
          <Button>aaa</Button>
        </div>
      )}
    </Authenticator>
  );
}

実装してみると...

0E51A4B5-D090-492A-9844-251476839B29.png

無事サインアウトできましたね。

さいごに

本日は Cloudscape Design System を導入した Next.js + Amplify アプリケーションの Top Navigation コンポーネントで Cognito からのサインアウトアクションを実装してみました。

私はフロントエンドの CSS が特に苦手だったのですが、Cloudscape Design System はそのまま適当に使えてとても良いですね。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.