11"use client" ;
22
3+ import { useState , useEffect , useRef } from "react" ;
34import { Avatar , AvatarFallback , AvatarImage } from "@/components/ui/avatar" ;
45import {
56 DropdownMenu ,
89 DropdownMenuSeparator ,
910 DropdownMenuTrigger ,
1011} from "@/components/ui/dropdown-menu" ;
11- import { LogOut } from "lucide-react" ;
12+ import { LogOut , Pencil } from "lucide-react" ;
1213import { useAuth } from "@/contexts/AuthContext" ;
14+ import { WelcomeDialog } from "@/components/WelcomeDialog" ;
1315
1416export default function Dashboard ( ) {
1517 const {
@@ -19,10 +21,28 @@ export default function Dashboard() {
1921 authStatus,
2022 lineProfile,
2123 userProfile,
24+ isNewUser,
2225 } = useAuth ( ) ;
26+ const [ showWelcomeDialog , setShowWelcomeDialog ] = useState ( false ) ;
27+ const hasShownWelcomeDialogRef = useRef ( false ) ;
2328 const profile = userProfile || lineProfile ;
29+
30+ // Show welcome dialog when a new user logs in, but only once
31+ useEffect ( ( ) => {
32+ if ( isNewUser && userProfile && ! hasShownWelcomeDialogRef . current ) {
33+ setShowWelcomeDialog ( true ) ;
34+ hasShownWelcomeDialogRef . current = true ;
35+ }
36+ } , [ isNewUser , userProfile ] ) ;
37+
2438 return (
2539 < div className = "jun-layout jun-layout-noTransition" >
40+ { /* Welcome Dialog for new users */ }
41+ < WelcomeDialog
42+ open = { showWelcomeDialog }
43+ onOpenChange = { setShowWelcomeDialog }
44+ />
45+
2646 < div className = "jun-header jun-header-h-[64px] jun-header-clip-left px-4 md:px-4" >
2747 < h1 className = "font-bold text-lg" > ⚡️ Jun MVP Starter</ h1 >
2848 < div className = "ml-auto" >
@@ -79,9 +99,30 @@ export default function Dashboard() {
7999 < div className = "px-4 py-3" >
80100 < div className = "font-medium" > { profile . displayName } </ div >
81101 { userProfile && (
82- < div className = "text-xs text-gray-500 truncate" >
83- { userProfile . providers ?. line ?. email || "LINE User" }
84- </ div >
102+ < >
103+ < div className = "text-xs text-gray-500 truncate" >
104+ { userProfile . providers ?. line ?. email || "LINE User" }
105+ </ div >
106+ { userProfile . description ? (
107+ < button
108+ onClick = { ( ) => setShowWelcomeDialog ( true ) }
109+ className = "mt-2 text-sm text-gray-600 italic group flex items-start w-full text-left hover:bg-gray-50 rounded px-1 py-0.5 transition-colors"
110+ >
111+ < Pencil className = "h-3.5 w-3.5 mr-1 mt-0.5 text-gray-400 group-hover:text-blue-500 flex-shrink-0" />
112+ < span className = "flex-1" >
113+ “{ userProfile . description } ”
114+ </ span >
115+ </ button >
116+ ) : (
117+ < button
118+ onClick = { ( ) => setShowWelcomeDialog ( true ) }
119+ className = "mt-2 text-xs text-blue-500 hover:underline flex items-center"
120+ >
121+ < Pencil className = "h-3 w-3 mr-1" />
122+ Add a description
123+ </ button >
124+ ) }
125+ </ >
85126 ) }
86127 </ div >
87128 < DropdownMenuSeparator className = "bg-gray-200" />
@@ -98,7 +139,7 @@ export default function Dashboard() {
98139 </ div >
99140 </ div >
100141 < main className = "jun-content" >
101- < div className = "container max-w-7xl py-8 px-4 2xl:w-full 2xl:max-w-fit 2xl:mx-[128px]" >
142+ < div className = "container mx-auto max-w-7xl py-8 px-4 2xl:w-full 2xl:max-w-fit 2xl:mx-[128px]" >
102143 < div className = "flex flex-col items-center text-center mb-12" >
103144 < h2 className = "text-3xl font-extrabold mb-1 bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 text-transparent bg-clip-text" >
104145 Go production in minutes
@@ -107,7 +148,7 @@ export default function Dashboard() {
107148 Next.js SSG, Line Login, Firebase
108149 </ p >
109150 < a
110- href = "https://github.com/siriwatknp/jun-mvp-starter/ "
151+ href = "https://github.com/siriwatknp/jun-stack "
111152 target = "_blank"
112153 rel = "noopener noreferrer"
113154 className = "inline-flex items-center gap-2 px-4 py-2 rounded-md bg-gray-100 hover:bg-gray-200 transition-colors text-sm font-bold"
@@ -159,6 +200,86 @@ export default function Dashboard() {
159200 </ p >
160201 </ div >
161202 </ div >
203+
204+ { /* Authentication Flow Section */ }
205+ < div className = "mt-16" >
206+ < h2 className = "text-2xl font-bold text-center mb-6" >
207+ Authentication Flow
208+ </ h2 >
209+ < div className = "bg-white rounded-lg shadow-md p-6" >
210+ < div className = "flex flex-col space-y-4" >
211+ < div className = "flex items-start" >
212+ < div className = "flex-shrink-0 bg-blue-100 rounded-full p-2 mr-4" >
213+ < span className = "font-bold text-blue-600" > 1</ span >
214+ </ div >
215+ < div >
216+ < h3 className = "font-medium" > LIFF Initialization</ h3 >
217+ < p className = "text-gray-600 text-sm" >
218+ The app initializes the LINE LIFF SDK and checks if the
219+ user is already logged in.
220+ </ p >
221+ </ div >
222+ </ div >
223+
224+ < div className = "flex items-start" >
225+ < div className = "flex-shrink-0 bg-green-100 rounded-full p-2 mr-4" >
226+ < span className = "font-bold text-green-600" > 2</ span >
227+ </ div >
228+ < div >
229+ < h3 className = "font-medium" > LINE Login</ h3 >
230+ < p className = "text-gray-600 text-sm" >
231+ User clicks the login button and is redirected to
232+ LINE's login page. After successful login,
233+ they're redirected back with authentication tokens.
234+ </ p >
235+ </ div >
236+ </ div >
237+
238+ < div className = "flex items-start" >
239+ < div className = "flex-shrink-0 bg-purple-100 rounded-full p-2 mr-4" >
240+ < span className = "font-bold text-purple-600" > 3</ span >
241+ </ div >
242+ < div >
243+ < h3 className = "font-medium" > Firebase Integration</ h3 >
244+ < p className = "text-gray-600 text-sm" >
245+ The app sends the LINE ID token to a Firebase Cloud
246+ Function, which verifies it and creates a Firebase custom
247+ token. It also creates or updates the user's document
248+ in Firestore.
249+ </ p >
250+ </ div >
251+ </ div >
252+
253+ < div className = "flex items-start" >
254+ < div className = "flex-shrink-0 bg-yellow-100 rounded-full p-2 mr-4" >
255+ < span className = "font-bold text-yellow-600" > 4</ span >
256+ </ div >
257+ < div >
258+ < h3 className = "font-medium" > User Session</ h3 >
259+ < p className = "text-gray-600 text-sm" >
260+ The app signs in to Firebase using the custom token and
261+ loads the user profile data from Firestore. Authentication
262+ state is maintained using React context.
263+ </ p >
264+ </ div >
265+ </ div >
266+
267+ < div className = "flex items-start" >
268+ < div className = "flex-shrink-0 bg-red-100 rounded-full p-2 mr-4" >
269+ < span className = "font-bold text-red-600" > 5</ span >
270+ </ div >
271+ < div >
272+ < h3 className = "font-medium" > Logout Process</ h3 >
273+ < p className = "text-gray-600 text-sm" >
274+ When logging out, the app signs out from both Firebase and
275+ LINE, and the UI is updated to show the login button
276+ again.
277+ </ p >
278+ </ div >
279+ </ div >
280+ </ div >
281+ </ div >
282+ </ div >
162283 </ div >
163284 </ main >
164285
0 commit comments