11/**
22 * Viz Magic — Onboarding / Character Creation Flow
3+ * New flow: after successful VIZ login without grimoire,
4+ * the user only chooses a class for the existing VIZ account.
35 */
46var OnboardingScreen = ( function ( ) {
57 'use strict' ;
68
7- var step = 0 ;
89 var selectedClass = '' ;
910 var mageName = '' ;
1011
1112 function render ( ) {
1213 var el = Helpers . $ ( 'screen-onboarding' ) ;
1314 if ( ! el ) return ;
14- step = 0 ;
15- _renderStep ( el ) ;
15+ _renderClassStep ( el , Helpers . t ) ;
1616 }
1717
18- function _renderStep ( el ) {
19- var t = Helpers . t ;
20- switch ( step ) {
21- case 0 : _renderNameStep ( el , t ) ; break ;
22- case 1 : _renderClassStep ( el , t ) ; break ;
23- case 2 : _renderLoginStep ( el , t ) ; break ;
24- }
25- }
26-
27- function _renderNameStep ( el , t ) {
28- el . innerHTML =
29- '<div class="onboarding-step">' +
30- '<h1>' + t ( 'onboarding_awaken_title' ) + '</h1>' +
31- '<p class="onboarding-text">' + t ( 'onboarding_awaken_text' ) . replace ( / \n / g, '<br>' ) + '</p>' +
32- '<label for="mage-name-input" class="input-label">' + t ( 'onboarding_name_prompt' ) + '</label>' +
33- '<input type="text" id="mage-name-input" class="input-field" ' +
34- 'aria-label="' + t ( 'onboarding_name_prompt' ) + '" ' +
35- 'autocomplete="off" maxlength="50" value="' + Helpers . escapeHtml ( mageName ) + '">' +
36- '<div id="name-feedback" class="input-feedback" aria-live="polite"></div>' +
37- '<button class="btn btn-primary btn-large" id="btn-name-next" disabled>' +
38- t ( 'onboarding_next' ) +
39- '</button>' +
40- '</div>' ;
41-
42- var input = Helpers . $ ( 'mage-name-input' ) ;
43- var feedback = Helpers . $ ( 'name-feedback' ) ;
44- var btn = Helpers . $ ( 'btn-name-next' ) ;
45-
46- input . addEventListener ( 'input' , Helpers . debounce ( function ( ) {
47- mageName = input . value . trim ( ) ;
48- if ( ! mageName ) {
49- feedback . textContent = '' ;
50- btn . disabled = true ;
51- return ;
52- }
53- if ( mageName . length < 2 ) {
54- feedback . textContent = t ( 'onboarding_name_invalid' ) ;
55- feedback . className = 'input-feedback error' ;
56- btn . disabled = true ;
57- return ;
58- }
59- feedback . textContent = '\u2728 ' + t ( 'onboarding_name_available' ) ;
60- feedback . className = 'input-feedback success' ;
61- btn . disabled = false ;
62- } , 300 ) ) ;
63-
64- btn . addEventListener ( 'click' , function ( ) {
65- if ( ! mageName ) return ;
66- SoundManager . play ( 'transition' ) ;
67- step = 1 ;
68- _renderStep ( el ) ;
69- } ) ;
70-
71- // BUG 3 FIX: Re-validate on render when returning via Back button
72- if ( mageName && mageName . length >= 2 ) {
73- feedback . textContent = '\u2728 ' + t ( 'onboarding_name_available' ) ;
74- feedback . className = 'input-feedback success' ;
75- btn . disabled = false ;
76- }
77-
78- input . focus ( ) ;
18+ function startForAccount ( account ) {
19+ selectedClass = '' ;
20+ mageName = ( account || '' ) . trim ( ) ;
7921 }
8022
8123 function _renderClassStep ( el , t ) {
@@ -89,6 +31,7 @@ var OnboardingScreen = (function() {
8931 var html = '<div class="onboarding-step">' +
9032 '<h1>' + t ( 'onboarding_class_title' ) + '</h1>' +
9133 '<p class="onboarding-text">' + t ( 'onboarding_class_text' ) . replace ( / \n / g, '<br>' ) + '</p>' +
34+ '<p class="onboarding-text">' + t ( 'onboarding_existing_account_notice' , { account : mageName || '' } ) + '</p>' +
9235 '<div class="class-grid" role="radiogroup" aria-label="' + t ( 'onboarding_class_title' ) + '">' ;
9336
9437 for ( var i = 0 ; i < classes . length ; i ++ ) {
@@ -107,9 +50,7 @@ var OnboardingScreen = (function() {
10750 html += '</div>' +
10851 '<div class="onboarding-buttons">' +
10952 '<button class="btn btn-secondary" id="btn-class-back">' + t ( 'onboarding_back' ) + '</button>' +
110- '<button class="btn btn-primary" id="btn-class-next" ' + ( selectedClass ? '' : 'disabled' ) + '>' +
111- t ( 'onboarding_next' ) +
112- '</button>' +
53+ '<button class="btn btn-primary" id="btn-class-next" ' + ( selectedClass ? '' : 'disabled' ) + '>' + t ( 'onboarding_next' ) + '</button>' +
11354 '</div></div>' ;
11455
11556 el . innerHTML = html ;
@@ -130,110 +71,48 @@ var OnboardingScreen = (function() {
13071 }
13172
13273 Helpers . $ ( 'btn-class-back' ) . addEventListener ( 'click' , function ( ) {
133- step = 0 ;
134- _renderStep ( el ) ;
74+ Helpers . EventBus . emit ( 'navigate' , 'login' ) ;
13575 } ) ;
13676
13777 Helpers . $ ( 'btn-class-next' ) . addEventListener ( 'click' , function ( ) {
13878 if ( ! selectedClass ) return ;
13979 SoundManager . play ( 'transition' ) ;
140- step = 2 ;
141- _renderStep ( el ) ;
80+ _createCharacterAndFinish ( ) ;
14281 } ) ;
14382 }
14483
145- /**
146- * Create character locally and on chain, then navigate home.
147- * BUG 1 FIX: Also creates the character in StateEngine immediately
148- * so Hunt and other screens can find it without waiting for chain.
149- * BUG 2 FIX: Called directly when user is already logged in.
150- */
15184 function _createCharacterAndFinish ( ) {
15285 var user = VizAccount . getCurrentUser ( ) ;
86+ if ( ! user ) {
87+ Helpers . EventBus . emit ( 'navigate' , 'login' ) ;
88+ return ;
89+ }
15390
154- // Create character locally in StateEngine so all screens see it immediately
91+ var displayName = mageName || user ;
15592 var state = StateEngine . getState ( ) ;
156- var character = CharacterSystem . createCharacter ( user , mageName , selectedClass ) ;
93+ var character = CharacterSystem . createCharacter ( user , displayName , selectedClass ) ;
15794 if ( character ) {
15895 state . characters [ user ] = character ;
15996 state . inventories [ user ] = state . inventories [ user ] || [ ] ;
97+ state . quests [ user ] = state . quests [ user ] || ( typeof QuestSystem !== 'undefined' ? QuestSystem . createPlayerQuestState ( ) : { } ) ;
16098 }
16199
162- // Broadcast to chain
163- var actionData = VMProtocol . createCharAttuneAction ( selectedClass , mageName ) ;
100+ var actionData = VMProtocol . createCharAttuneAction ( selectedClass , displayName ) ;
164101 VizBroadcast . gameAction ( actionData , function ( err2 ) {
165102 if ( err2 ) {
166103 console . log ( 'Char attune broadcast error (may already exist):' , err2 ) ;
167104 }
168105 } ) ;
169106
170- // Save grimoire to blockchain so character persists across page reloads
171- VizAccount . updateGrimoire ( { class : selectedClass , name : mageName } , function ( err3 ) {
107+ VizAccount . updateGrimoire ( { class : selectedClass , name : displayName } , function ( err3 ) {
172108 if ( err3 ) {
173109 console . log ( 'Grimoire save error:' , err3 ) ;
174- } else {
175- console . log ( 'Grimoire saved to chain for' , user ) ;
176110 }
177111 } ) ;
178112
179113 SoundManager . play ( 'success' ) ;
180114 Helpers . EventBus . emit ( 'navigate' , 'home' ) ;
181115 }
182116
183- function _renderLoginStep ( el , t ) {
184- // BUG 2 FIX: If user is already logged in, skip the login form
185- var currentUser = VizAccount . getCurrentUser ( ) ;
186- if ( currentUser ) {
187- _createCharacterAndFinish ( ) ;
188- return ;
189- }
190-
191- el . innerHTML =
192- '<div class="onboarding-step">' +
193- '<h1>' + t ( 'login_title' ) + '</h1>' +
194- '<p class="onboarding-text">' +
195- 'Class: ' + Helpers . classIcon ( selectedClass ) + ' ' + t ( 'class_' + selectedClass ) +
196- '<br>Name: ' + Helpers . escapeHtml ( mageName ) +
197- '</p>' +
198- '<label for="login-account" class="input-label">' + t ( 'login_account' ) + '</label>' +
199- '<input type="text" id="login-account" class="input-field" autocomplete="username">' +
200- '<label for="login-key" class="input-label">' + t ( 'login_key' ) + '</label>' +
201- '<input type="password" id="login-key" class="input-field" autocomplete="current-password">' +
202- '<div id="login-error" class="input-feedback error" aria-live="polite"></div>' +
203- '<button class="btn btn-primary btn-large" id="btn-login-submit">' +
204- t ( 'login_submit' ) +
205- '</button>' +
206- '<button class="btn btn-secondary" id="btn-login-back">' + t ( 'onboarding_back' ) + '</button>' +
207- '</div>' ;
208-
209- Helpers . $ ( 'btn-login-back' ) . addEventListener ( 'click' , function ( ) {
210- step = 1 ;
211- _renderStep ( el ) ;
212- } ) ;
213-
214- Helpers . $ ( 'btn-login-submit' ) . addEventListener ( 'click' , function ( ) {
215- var account = Helpers . $ ( 'login-account' ) . value . trim ( ) ;
216- var key = Helpers . $ ( 'login-key' ) . value . trim ( ) ;
217- var errorEl = Helpers . $ ( 'login-error' ) ;
218-
219- if ( ! account || ! key ) {
220- errorEl . textContent = t ( 'login_error_empty' ) ;
221- return ;
222- }
223-
224- errorEl . textContent = Helpers . t ( 'loading' ) ;
225- VizAccount . login ( account , key , function ( err ) {
226- if ( err ) {
227- if ( err . message === 'account_not_found' ) errorEl . textContent = t ( 'login_error_not_found' ) ;
228- else if ( err . message === 'invalid_regular_key' ) errorEl . textContent = t ( 'login_error_wrong_key' ) ;
229- else errorEl . textContent = err . message ;
230- return ;
231- }
232-
233- _createCharacterAndFinish ( ) ;
234- } ) ;
235- } ) ;
236- }
237-
238- return { render : render } ;
117+ return { render : render , startForAccount : startForAccount } ;
239118} ) ( ) ;
0 commit comments