File size: 4,821 Bytes
68f7925
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
'use client';
import { AppBar } from '@/components/parts/app-bar';
import { Bread } from '@/components/parts/bread';
import { OldAppBar } from '@/components/parts/old-app-bar';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import { sendLog } from '@/services/gradio';
import { useStateStore } from '@/store/state';
import { type UserState, useUserStore } from '@/store/user';
import { SessionProvider, getProviders, signIn, useSession } from 'next-auth/react';
import Image from 'next/image';
import { usePathname } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';

export function AuthWrapper({ children }: { children: React.ReactNode }) {
  return (
    <SessionProvider>
      <InnerAuthWrapper>{children}</InnerAuthWrapper>
    </SessionProvider>
  );
}

function InnerAuthWrapper({ children }: { children: React.ReactNode }) {
  const { data: session, status } = useSession();
  const { setUser } = useUserStore();
  const logSentRef = useRef(false);
  const [hasOktaProvider, setHasOktaProvider] = useState<boolean | null>(null);

  const isProduction = process.env.NEXT_PUBLIC_APP_ENV === 'production';

  // NextAuthで利用可能なプロバイダーをチェック
  useEffect(() => {
    getProviders().then((providers) => {
      setHasOktaProvider(!!providers?.okta);
    });
  }, []);

  useEffect(() => {
    setUser(session as UserState);

    // Send log only once when user logs in
    if (session?.user?.email && !logSentRef.current) {
      sendLog(session.user.email);
      logSentRef.current = true;
    }
  }, [session, setUser]);

  const pathname = usePathname();
  const { getScoreLoading, getMomentLoading } = useStateStore();
  const showBreadOnPages = [
    '/',
    '/speed-comparison-input',
    '/speed-comparison-result',
    '/prediction-input',
    '/prediction-result',
    '/detail',
    '/refresh-moments',
    '/refresh-moments/result',
  ];

  // プロバイダーチェック中はローディング表示
  if (hasOktaProvider === null) {
    return (
      <div className="flex min-h-screen items-center justify-center">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-gray-500 border-t-transparent"></div>
      </div>
    );
  }

  // Oktaプロバイダーが利用できない場合は認証をスキップ
  if (!hasOktaProvider) {
    return (
      <>
        {isProduction ? <OldAppBar email="dev@example.com" /> : <AppBar email="dev@example.com" />}
        <main className="relative flex grow flex-col space-y-2">
          <video
            className={cn('background-video', pathname === '/error' || getScoreLoading ? 'opacity-20' : 'opacity-50')}
            src="/background.mp4"
            autoPlay
            loop
            playsInline
            muted
          />
          <div className="z-10 flex grow flex-col p-12">
            {!getScoreLoading && !getMomentLoading && showBreadOnPages.includes(pathname) ? <Bread /> : null}
            {children}
          </div>
        </main>
      </>
    );
  }

  // 本番環境では認証を有効化
  if (status === 'loading') {
    return (
      <div className="flex min-h-screen items-center justify-center">
        <div className="h-8 w-8 animate-spin rounded-full border-4 border-gray-500 border-t-transparent"></div>
      </div>
    );
  }

  if (status === 'unauthenticated') {
    return (
      <div className="relative flex min-h-screen flex-col items-center justify-center">
        {/* 背景ビデオ */}
        <video className="background-video opacity-50" src="/background.mp4" autoPlay loop playsInline muted />

        {/* ログインカード */}
        <div className="z-10 w-full max-w-md rounded-xl bg-white/80 p-8">
          <div className="mb-8 flex flex-col items-center">
            <Image src="/logo.svg" alt="logo" width={120} height={60} className="mb-4" />
          </div>

          <Button onClick={() => signIn('okta')} variant="gradient">
            Oktaでログイン
          </Button>
        </div>
      </div>
    );
  }

  if (session) {
    return (
      <>
        {isProduction ? <OldAppBar email={session?.user?.email ?? ''} /> : <AppBar email={session?.user?.email ?? ''} />}
        <main className="relative flex grow flex-col space-y-2">
          <video
            className={cn('background-video', pathname === '/error' || getScoreLoading ? 'opacity-20' : 'opacity-50')}
            src="/background.mp4"
            autoPlay
            loop
            playsInline
            muted
          />
          <div className="z-10 flex grow flex-col p-12">
            {!getScoreLoading && !getMomentLoading && showBreadOnPages.includes(pathname) ? <Bread /> : null}
            {children}
          </div>
        </main>
      </>
    );
  }
}