File size: 9,575 Bytes
ae79a68
449276f
901982e
ae79a68
901982e
449276f
 
 
 
 
 
 
 
901982e
449276f
 
 
1662a78
449276f
 
 
 
 
1662a78
449276f
 
 
 
 
 
 
 
 
901982e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449276f
ae79a68
 
 
449276f
 
 
 
 
 
901982e
 
 
 
 
 
 
 
ae79a68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
901982e
 
 
 
 
 
 
 
 
ae79a68
 
 
901982e
ae79a68
 
66269b4
ae79a68
 
 
 
 
 
 
66269b4
ae79a68
 
66269b4
ae79a68
 
 
901982e
 
 
 
 
 
b391d41
 
901982e
 
 
ae79a68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import { createRoom, joinRoom, checkNicknameConflict } from "../services/classroom.js";
import { generateMonsterSVG, MONSTER_DEFS } from "../utils/monsterUtils.js";

// ... (renderLandingView remains same) ...
export function renderLandingView() {
    // Select Decor Monsters
    // Left: Genesis Dragon (L3_AAA), Right: Gundam (L3_BAA) - or fallbacks
    const mLeft = MONSTER_DEFS.find(m => m.id === 'L3_AAA') || MONSTER_DEFS.find(m => m.stage === 3);
    const mRight = MONSTER_DEFS.find(m => m.id === 'L3_BAA') || MONSTER_DEFS.find(m => m.stage === 3);

    const svgLeft = generateMonsterSVG(mLeft);
    const svgRight = generateMonsterSVG(mRight);

    return `

    <div class="min-h-screen flex flex-col items-center justify-center p-4 relative overflow-hidden">

        

        <!-- Decor Monsters (Desktop Only) -->

        <div class="absolute bottom-10 left-10 w-48 h-48 hidden lg:block pointer-events-none" 

             style="animation: float 6s ease-in-out infinite;">

             <div class="w-full h-full drop-shadow-[0_0_15px_rgba(34,211,238,0.5)]">

                ${svgLeft}

             </div>

        </div>

        <div class="absolute bottom-10 right-10 w-48 h-48 hidden lg:block pointer-events-none" 

             style="animation: float 8s ease-in-out infinite reverse;">

             <div class="w-full h-full drop-shadow-[0_0_15px_rgba(59,130,246,0.5)]">

                ${svgRight}

             </div>

        </div>



        <div class="max-w-md w-full bg-gray-600 bg-opacity-20 backdrop-blur-lg rounded-xl shadow-2xl p-8 border border-gray-700 z-10">

            <h1 class="text-3xl sm:text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-purple-500 mb-8 text-center tracking-tighter whitespace-nowrap">

                VIBECODING-怪獸成長營

            </h1>

            

            <!-- Student Join Form -->

            <div id="student-form" class="space-y-6">

                <div>

                    <label class="block text-gray-400 text-sm font-bold mb-2">教室代碼 (Room Code)</label>

                    <input type="text" id="room-code-input" class="w-full bg-gray-800 text-white border border-gray-600 rounded-lg py-3 px-4 focus:outline-none focus:border-cyan-500 transition-colors" placeholder="1234">

                </div>

                <div>

                    <label class="block text-gray-400 text-sm font-bold mb-2">您的暱稱 (Nickname)</label>

                    <input type="text" id="nickname-input" class="w-full bg-gray-800 text-white border border-gray-600 rounded-lg py-3 px-4 focus:outline-none focus:border-purple-500 transition-colors" placeholder="小明">

                </div>

                <button id="join-btn" class="w-full bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 text-white font-bold py-3 px-4 rounded-lg transform transition hover:scale-105 active:scale-95 shadow-lg shadow-cyan-500/30">

                    進入教室

                </button>

            </div>



            <!-- Instructor Toggle -->

            <div class="mt-8 pt-6 border-t border-gray-700 text-center">

                <button id="instructor-mode-btn" class="text-gray-500 text-sm hover:text-cyan-400 transition-colors">

                    我是講師 (Instructor Mode)

                </button>

            </div>

        </div>

        

        <!-- Conflict Modal Container -->

        <div id="conflict-modal-container"></div>



        <style>

            @keyframes float {

                0%, 100% { transform: translateY(0); }

                50% { transform: translateY(-20px); }

            }

        </style>

    </div>

    `;
}

export function setupLandingEvents(navigateTo) {
    const joinBtn = document.getElementById('join-btn');
    const instructorBtn = document.getElementById('instructor-mode-btn');

    const handleJoin = async (roomCode, nickname, forceNew = false) => {
        try {
            const { userId, nickname: finalNickname } = await joinRoom(roomCode, nickname, forceNew);

            // Save Session
            localStorage.setItem('vibecoding_user_id', userId);
            localStorage.setItem('vibecoding_room_code', roomCode);
            localStorage.setItem('vibecoding_nickname', finalNickname);

            navigateTo('student');
            return true;
        } catch (error) {
            alert('加入失敗: ' + error.message);
            return false;
        }
    };

    joinBtn.addEventListener('click', async () => {
        const roomCode = document.getElementById('room-code-input').value.trim();
        const nickname = document.getElementById('nickname-input').value.trim();

        if (!roomCode || !nickname) {
            alert('請輸入教室代碼和暱稱');
            return;
        }

        joinBtn.textContent = '檢查中...';
        joinBtn.disabled = true;

        try {
            // Check conflicts first
            const conflicts = await checkNicknameConflict(roomCode, nickname);

            if (conflicts.length > 0) {
                // Show Conflict Modal
                showConflictModal(conflicts, nickname, roomCode, navigateTo, handleJoin);
                joinBtn.textContent = '進入教室';
                joinBtn.disabled = false;
                return;
            }

            // No conflict -> direct join
            await handleJoin(roomCode, nickname);

        } catch (e) {
            console.error(e);
            alert("檢查失敗: " + e.message);
            joinBtn.textContent = '進入教室';
            joinBtn.disabled = false;
        }
    });

    instructorBtn.addEventListener('click', () => {
        // Clear any previous admin referer to ensure clean state
        localStorage.removeItem('vibecoding_admin_referer');
        navigateTo('instructor');
    });
}

function showConflictModal(conflicts, originalNickname, roomCode, navigateTo, handleJoin) {
    const container = document.getElementById('conflict-modal-container');

    const userListHTML = conflicts.map(u => `

        <button onclick="window.selectUser('${u.nickname}')" 

            class="w-full text-left bg-gray-700 hover:bg-gray-600 p-4 rounded-xl flex justify-between items-center group transition-all border border-gray-600 hover:border-cyan-500">

            <span class="font-bold text-white group-hover:text-cyan-300 transition-colors">${u.nickname}</span>

            <span class="text-xs text-gray-400 bg-gray-800 px-2 py-1 rounded">舊學員</span>

        </button>

    `).join('');

    container.innerHTML = `

        <div class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">

            <div class="bg-gray-800 w-full max-w-md rounded-2xl border border-gray-700 shadow-2xl overflow-hidden animate-[fadeIn_0.3s_ease-out]">

                <div class="p-6 border-b border-gray-700 bg-gray-900/50">

                    <h3 class="text-xl font-bold text-white mb-1">發現相同暱稱</h3>

                    <p class="text-gray-400 text-sm">教室裡已經有叫「${originalNickname}」的同學了,請問您是?</p>

                </div>

                

                <div class="p-6 space-y-3 max-h-[60vh] overflow-y-auto">

                    ${userListHTML}

                    

                    <div class="relative flex py-2 items-center">

                        <div class="flex-grow border-t border-gray-700"></div>

                        <span class="flex-shrink-0 mx-4 text-gray-500 text-xs">或者</span>

                        <div class="flex-grow border-t border-gray-700"></div>

                    </div>



                    <button onclick="window.createNewUser()" 

                        class="w-full bg-gradient-to-r from-green-600 to-teal-600 hover:from-green-500 hover:to-teal-500 text-white font-bold p-4 rounded-xl shadow-lg shadow-green-900/40 transform transition hover:scale-[1.02] flex items-center justify-center space-x-2">

                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">

                            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-11a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V7z" clip-rule="evenodd" />

                        </svg>

                        <span>我是新同學,建立新分身</span>

                    </button>

                </div>



                <div class="p-4 bg-gray-900/50 border-t border-gray-700 flex justify-end">

                    <button onclick="document.getElementById('conflict-modal-container').innerHTML=''" 

                        class="text-gray-400 hover:text-white text-sm px-4 py-2">

                        取消

                    </button>

                </div>

            </div>

        </div>

    `;

    // Bind temporary window functions for the modal buttons
    window.selectUser = async (targetNickname) => {
        // Log in as existing
        document.getElementById('conflict-modal-container').innerHTML = ''; // Close modal
        await handleJoin(roomCode, targetNickname, false);
    };

    window.createNewUser = async () => {
        // Create new
        document.getElementById('conflict-modal-container').innerHTML = ''; // Close modal
        await handleJoin(roomCode, originalNickname, true); // Force new
    };
}