PageSourceSearch

https://attachment-manager-iidrovog.replit.app/wallet

html attachment-manager-iidrovog.replit.app collected 2026-10-03 03:47:23 UTC 13,796 bytes, 355 lines download raw bytes

1
2    <!DOCTYPE html>
3    <html lang="en">
4    <head>
5        <meta charset="UTF-8">
6        <meta name="viewport" content="width=device-width, initial-scale=1.0">
7        <title>ShiftLoop Wallet</title>
8        <style>
9            body { 
10                background-color: #1a202c; 
11                color: white; 
12                font-family: system-ui, -apple-system, sans-serif; 
13                margin: 0; 
14                padding: 0;
15                line-height: 1.5;
16            }
17            .container { 
18                max-width: 600px; 
19                margin: 0 auto; 
20                padding: 20px; 
21            }
22            header { 
23                text-align: center; 
24                margin: 30px 0; 
25            }
26            header h1 { 
27                margin-bottom: 10px; 
28            }
29            header p { 
30                color: #a0aec0; 
31                margin: 0; 
32            }
33            .card { 
34                background-color: #2d3748; 
35                border-radius: 8px; 
36                padding: 20px; 
37                margin-bottom: 20px; 
38                box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
39            }
40            .row { 
41                display: flex; 
42                justify-content: space-between; 
43                align-items: center; 
44                margin-bottom: 10px; 
45            }
46            .progress-container { 
47                height: 20px; 
48                background-color: #4a5568; 
49                border-radius: 9999px; 
50                overflow: hidden; 
51                margin-bottom: 20px; 
52                position: relative;
53            }
54            .progress-bar { 
55                height: 100%; 
56                background-color: #6b46c1; 
57                width: 0%;
58                position: relative;
59                overflow: hidden;
60            }
61            .progress-bar::after {
62                content: '';
63                position: absolute;
64                top: 0;
65                left: 0;
66                width: 100%;
67                height: 100%;
68                background-image: linear-gradient(
69                    45deg,
70                    rgba(255, 255, 255, 0.2) 25%,
71                    transparent 25%,
72                    transparent 50%,
73                    rgba(255, 255, 255, 0.2) 50%,
74                    rgba(255, 255, 255, 0.2) 75%,
75                    transparent 75%,
76                    transparent
77                );
78                background-size: 30px 30px;
79                animation: progress-animation 1s linear infinite;
80                z-index: 1;
81            }
82            @keyframes progress-animation {
83                0% { background-position: 0 0; }
84                100% { background-position: 30px 0; }
85            }
86            h2, h3 { 
87                margin-top: 0; 
88            }
89            .mt-4 { 
90                margin-top: 20px; 
91            }
92            .btn { 
93                background-color: #6b46c1; 
94                color: white; 
95                border: none; 
96                padding: 10px 16px; 
97                border-radius: 4px; 
98                cursor: pointer; 
99                display: inline-block; 
100                text-decoration: none; 
101            }
102            .btn:disabled { 
103                opacity: 0.7; 
104                cursor: not-allowed; 
105            }
106            .btn:hover:not(:disabled) { 
107                background-color: #553c9a; 
108            }
109            .text-muted { 
110                color: #a0aec0; 
111            }
112            .footer { 
113                text-align: center; 
114                margin-top: 20px; 
115            }
116            .footer a { 
117                color: #a0aec0; 
118                text-decoration: none; 
119            }
120            .footer a:hover { 
121                text-decoration: underline; 
122            }
123            .badge-container {
124                background-color: #374151;
125                border-radius: 8px;
126                padding: 20px;
127                margin-top: 20px;
128                text-align: center;
129            }
130            .badge-icon {
131                width: 120px;
132                height: 120px;
133                background-color: #6b46c1;
134                border-radius: 50%;
135                margin: 0 auto 15px;
136                display: flex;
137                align-items: center;
138                justify-content: center;
139                font-size: 40px;
140            }
141            .badge-info {
142                margin-bottom: 15px;
143            }
144            .navbar {
145                background-color: #2d3748;
146                padding: 15px 0;
147                margin-bottom: 20px;
148                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
149            }
150            .navbar-container {
151                display: flex;
152                justify-content: space-between;
153                align-items: center;
154                padding: 0 20px;
155            }
156            .nav-link {
157                color: white;
158                text-decoration: none;
159            }
160            .dev-tools {
161                margin-top: 20px;
162                border: 1px solid #553c9a;
163                background-color: rgba(102, 51, 153, 0.1);
164            }
165        </style>
166        <!-- Add manifest link for PWA -->
167        <link rel="manifest" href="/manifest.json">
168        <!-- iOS support -->
169        <meta name="apple-mobile-web-app-capable" content="yes">
170        <meta name="apple-mobile-web-app-status-bar-style" content="black">
171        <meta name="apple-mobile-web-app-title" content="ShiftLoop Wallet">
172        <link rel="apple-touch-icon" href="/icon-192x192.png">
173        <meta name="theme-color" content="#1a202c">
174        <!-- Alpine.js -->
175        
175<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
175
176    </head>
177    <body>
178        <nav class="navbar">
179            <div class="navbar-container container">
180                <a href="/" class="nav-link">ShiftLoop</a>
181                <a href="/dashboard" class="nav-link">Dashboard</a>
182            </div>
183        </nav>
184        
185        <div class="container" x-data="{
186            phone: '123456789',
187            xp: 0,
188            maxXp: 50,
189            progress: 0,
190            lessonCount: 79,
191            completedLessons: 0,
192            badgeTx: 'None' || null,
193            init() {
194                // Initialize progress bar
195                setTimeout(() => {
196                    this.animateProgress()
197                }, 500)
198                
199                // Set up auto-refresh
200                this.setupRefresh()
201                
202                // Register service worker
203                this.registerServiceWorker()
204                
205                // Load cached data from localStorage
206                this.loadCachedData()
207            },
208            animateProgress() {
209                document.getElementById('xp-progress').style.transition = 'width 1s ease-in-out'
210                document.getElementById('xp-progress').style.width = this.progress + '%'
211            },
212            setupRefresh() {
213                // Auto-refresh progress data every 30 seconds
214                setInterval(() => {
215                    fetch(`/api/progress?phone=${this.phone}`)
216                        .then(res => res.json())
217                        .then(data => {
218                            if (data.xp !== undefined) {
219                                this.xp = data.xp
220                                this.progress = Math.min(100, parseInt((data.xp / this.maxXp) * 100))
221                                document.getElementById('xp-progress').style.width = this.progress + '%'
222                                
223                                // Store in localStorage for offline
224                                localStorage.setItem('shiftloop_xp', data.xp)
225                                localStorage.setItem('shiftloop_progress', this.progress)
226                                localStorage.setItem('shiftloop_phone', this.phone)
227                                localStorage.setItem('shiftloop_updated', new Date().toISOString())
228                            }
229                        })
230                        .catch(err => {
231                            console.log('Could not update progress data. Using cached data.')
232                        })
233                }, 30000)
234            },
235            registerServiceWorker() {
236                if ('serviceWorker' in navigator) {
237                    window.addEventListener('load', () => {
238                        navigator.serviceWorker.register('/service-worker.js')
239                            .then(reg => console.log('ServiceWorker registration successful'))
240                            .catch(err => console.log('ServiceWorker registration failed', err))
241                    })
242                }
243            },
244            loadCachedData() {
245                // If we have cached data and are offline, use it
246                if (!navigator.onLine) {
247                    const cachedXp = localStorage.getItem('shiftloop_xp')
248                    const cachedProgress = localStorage.getItem('shiftloop_progress')
249                    if (cachedXp && cachedProgress) {
250                        this.xp = parseInt(cachedXp)
251                        this.progress = parseInt(cachedProgress)
252                        this.animateProgress()
253                    }
254                }
255            },
256            simulateXpChange() {
257                fetch(`/dev/simulate-xp/${this.phone}`)
258                    .then(res => res.json())
259                    .then(data => {
260                        console.log('XP updated:', data)
261                        if (data.new_xp !== undefined) {
262                            this.xp = data.new_xp
263                            this.progress = Math.min(100, parseInt((data.new_xp / this.maxXp) * 100))
264                            this.animateProgress()
265                        }
266                    })
267                    .catch(err => console.error('Error simulating XP change:', err))
268            },
269            createTestUser() {
270                fetch(`/dev/create-test-user/${this.phone}`)
271                    .then(res => res.json())
272                    .then(data => {
273                        console.log('Test user created/updated:', data)
274                        location.reload()
275                    })
276                    .catch(err => console.error('Error creating test user:', err))
277            }
278        }">
279            <header>
280                <h1>ShiftLoop Wallet</h1>
281                <p>Your Web3 bootcamp achievements</p>
282            </header>
283
284            <div class="card">
285                <h2>Your Progress</h2>
286                <div class="row">
287                    <span>Experience Points (XP)</span>
288                    <span x-text="xp + '/' + maxXp">0/50</span>
289                </div>
290                <div class="progress-container">
291                    <div class="progress-bar" id="xp-progress"></div>
292                </div>
293                
294                <div class="row">
295                    <span>Lessons Completed</span>
296                    <span x-text="completedLessons + '/' + lessonCount">0/79</span>
297                </div>
298            </div>
299            
300            <div class="card">
301                <h2>NFT Badge</h2>
302                <template x-if="badgeTx">
303                    <div class='badge-container'>
304                        <div class='badge-icon'>🏆</div>
305                        <h3 class='badge-info'>Web3 Bootcamp Graduate</h3>
306                        <p>Congratulations! You've earned a blockchain-verified credential.</p>
307                        <p class='text-muted'>
308                            Transaction: 
309                            <a :href="'https://polygonscan.com/tx/' + badgeTx" target='_blank' style='color:#a0aec0;' 
310                               x-text="badgeTx.substring(0,8) + '...' + badgeTx.substring(badgeTx.length-6)">
311                               
312                            </a>
313                        </p>
314                        <div class='mt-4'>
315                            <a href='#' class='btn'>Share with Friends</a>
316                        </div>
317                    </div>
318                </template>
319                <template x-if="!badgeTx">
320                    <div>
321                        <p>Complete all lessons to earn your blockchain-verified badge!</p>
322                        <div class='mt-4'>
323                            <button class='btn' disabled>Share with Friends</button>
324                        </div>
325                    </div>
326                </template>
327            </div>
328            
329            <div class="card">
330                <div class="row">
331                    <div>
332                        <h3 style="margin:0;">Offline Mode</h3>
333                        <p class="text-muted" style="margin:0;">This wallet works offline after your first visit!</p>
334                    </div>
335                    <div class="badge-icon" style="width:40px;height:40px;font-size:20px;background-color:#38a169;">✓</div>
336                </div>
337            </div>
338            
339            <!-- Development tools (only visible in development) -->
340            <div class="card dev-tools">
341                <h2>Development Tools</h2>
342                <p class="text-muted">These controls are for testing only</p>
343                <div style="display: flex; gap: 10px; margin-top: 15px;">
344                    <button @click="simulateXpChange()" class="btn">Simulate XP Change</button>
345                    <button @click="createTestUser()" class="btn" style="background-color: #4299e1;">Create Test User</button>
346                </div>
347            </div>
348            
349            <div class="footer">
350                <a href="/dashboard">← Back to Dashboard</a>
351            </div>
352        </div>
353    </body>
354    </html>
355    

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.