Raw
1 <script>
2 import Greet from "./lib/Greet.svelte";
3 import { open, close } from "tauri-plugin-ios-window-api";
4
5 // Environment configuration
6 let environment = $state("production"); // Toggle between "production" and "development"
7
8 $effect(() => {
9 console.log(`Environment: ${environment}`);
10 });
11
12 function getBaseUrl() {
13 return environment === "production"
14 ? "https://splitfire.ai"
15 : "https://splitfire-ai-local.com:3333";
16 }
17
18 function openTauriWebsite() {
19 open("https://tauri.app", "Tauri")
20 .then(() => {
21 console.log("Tauri website opened successfully");
22 })
23 .catch((error) => {
24 console.error("Failed to open window:", error);
25 });
26 }
27
28 async function signInWithApple() {
29 try {
30 const baseUrl = getBaseUrl();
31
32 // OAuth callback configuration
33 // Option 1: Custom URL scheme (recommended for mobile)
34 // const redirectUri = "splitfire://oauth/callback";
35
36 // Option 2: Localhost server (for testing/desktop)
37 const redirectUri = "http://localhost:8080/oauth/callback";
38
39 // Build the OAuth URL following SplitFire pattern
40 const redirectUrl = `${baseUrl}/synch-apple/auth?redirect_uri=${encodeURIComponent(redirectUri)}`;
41
42 console.log(`Opening Apple OAuth: ${redirectUrl}`);
43 console.log(`Callback will be sent to: ${redirectUri}`);
44
45 // Open the OAuth window
46 await open(redirectUrl, "Sign in with Apple");
47 console.log("Apple OAuth window opened successfully");
48
49 // TODO: Implement OAuth callback handling
50 // 1. Set up a listener for the redirect URI (deep link or local server)
51 // 2. Parse the authorization code/token from the callback
52 // 3. Send to your backend for validation
53 // 4. Store the user session
54
55 // Example callback handler (pseudo-code):
56 // listen("oauth-callback", (event) => {
57 // const { code, state } = event.payload;
58 // // Exchange code for access token via backend
59 // fetch(`${baseUrl}/api/oauth/apple/token`, {
60 // method: "POST",
61 // body: JSON.stringify({ code, redirect_uri: redirectUri })
62 // });
63 // });
64 } catch (error) {
65 console.error("Failed to open Apple OAuth:", error);
66 }
67 }
68
69 // Complete OAuth flow example with callback handling
70 async function completeOAuthFlow() {
71 try {
72 const baseUrl = getBaseUrl();
73 const redirectUri = "http://localhost:8080/oauth/callback";
74 const redirectUrl = `${baseUrl}/synch-apple/auth?redirect_uri=${encodeURIComponent(redirectUri)}`;
75
76 console.log("Starting OAuth flow...");
77 await open(redirectUrl, "Sign in with Apple");
78
79 // Simulate OAuth callback after 3 seconds
80 setTimeout(async () => {
81 console.log("OAuth callback received (simulated)");
82 console.log("Processing authentication...");
83
84 // Simulate token exchange
85 setTimeout(async () => {
86 console.log("✓ Authentication successful!");
87 console.log("Closing OAuth window...");
88
89 // Close the window after successful auth
90 await close();
91 console.log("✓ OAuth flow complete");
92
93 // Show success message to user
94 alert("Successfully signed in with Apple!");
95 }, 1000);
96 }, 3000);
97 } catch (error) {
98 console.error("OAuth flow failed:", error);
99 }
100 }
101
102 async function openWithAutoClose() {
103 try {
104 const baseUrl = getBaseUrl();
105 const redirectUri = "http://localhost:8080/oauth/callback";
106 const redirectUrl = `${baseUrl}/synch-apple/auth?redirect_uri=${encodeURIComponent(redirectUri)}`;
107
108 await open(redirectUrl, "Auto-close Demo");
109 console.log("Window opened, will auto-close in 5 seconds...");
110
111 // Auto-close after 5 seconds
112 setTimeout(async () => {
113 try {
114 await close();
115 console.log("Window closed programmatically");
116 } catch (error) {
117 console.error("Failed to close window:", error);
118 }
119 }, 5000);
120 } catch (error) {
121 console.error("Failed to open window:", error);
122 }
123 }
124
125 async function closeWindow() {
126 try {
127 await close();
128 console.log("Window closed successfully");
129 } catch (error) {
130 console.error("Failed to close window:", error);
131 }
132 }
133
134 function toggleEnvironment() {
135 environment =
136 environment === "production" ? "development" : "production";
137 }
138 </script>
139
140 <main class="container">
141 <h1>Welcome to Tauri!</h1>
142
143 <div class="row">
144 <a href="https://vite.dev" target="_blank">
145 <img src="/vite.svg" class="logo vite" alt="Vite Logo" />
146 </a>
147 <a href="https://tauri.app" target="_blank">
148 <img src="/tauri.svg" class="logo tauri" alt="Tauri Logo" />
149 </a>
150 <a href="https://svelte.dev" target="_blank">
151 <img src="/svelte.svg" class="logo svelte" alt="Svelte Logo" />
152 </a>
153 </div>
154
155 <p>Click on the Tauri, Vite, and Svelte logos to learn more.</p>
156
157 <div class="row">
158 <Greet />
159 </div>
160
161 <div class="button-container">
162 <!-- Environment Toggle -->
163 <div class="environment-toggle">
164 <button onclick={toggleEnvironment} class="btn btn-secondary">
165 Environment: {environment}
166 </button>
167 <p class="environment-url">{getBaseUrl()}</p>
168 </div>
169
170 <button onclick={openTauriWebsite} class="btn btn-primary">
171 Open Tauri Website
172 </button>
173
174 <button onclick={signInWithApple} class="btn btn-apple">
175 <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
176 <path
177 d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"
178 />
179 </svg>
180 Sign in with Apple (SplitFire)
181 </button>
182
183 <button onclick={completeOAuthFlow} class="btn btn-success">
184 <svg
185 width="20"
186 height="20"
187 viewBox="0 0 24 24"
188 fill="none"
189 stroke="currentColor"
190 stroke-width="2"
191 >
192 <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
193 <polyline points="22 4 12 14.01 9 11.01"></polyline>
194 </svg>
195 Complete OAuth Flow Demo
196 </button>
197
198 <button onclick={openWithAutoClose} class="btn btn-warning">
199 <svg
200 width="20"
201 height="20"
202 viewBox="0 0 24 24"
203 fill="none"
204 stroke="currentColor"
205 stroke-width="2"
206 >
207 <circle cx="12" cy="12" r="10"></circle>
208 <polyline points="12 6 12 12 16 14"></polyline>
209 </svg>
210 Auto-close Demo (5s)
211 </button>
212
213 <button onclick={closeWindow} class="btn btn-danger">
214 <svg
215 width="20"
216 height="20"
217 viewBox="0 0 24 24"
218 fill="none"
219 stroke="currentColor"
220 stroke-width="2"
221 >
222 <line x1="18" y1="6" x2="6" y2="18"></line>
223 <line x1="6" y1="6" x2="18" y2="18"></line>
224 </svg>
225 Close Window
226 </button>
227 </div>
228 </main>
229
230 <style>
231 .logo.vite:hover {
232 filter: drop-shadow(0 0 2em #747bff);
233 }
234
235 .logo.svelte:hover {
236 filter: drop-shadow(0 0 2em #ff3e00);
237 }
238
239 .button-container {
240 display: flex;
241 flex-direction: column;
242 gap: 1rem;
243 margin-top: 2rem;
244 max-width: 300px;
245 margin-left: auto;
246 margin-right: auto;
247 }
248
249 .btn {
250 padding: 0.75rem 1.5rem;
251 border: none;
252 border-radius: 8px;
253 font-size: 1rem;
254 font-weight: 600;
255 cursor: pointer;
256 transition: all 0.3s ease;
257 display: flex;
258 align-items: center;
259 justify-content: center;
260 gap: 0.5rem;
261 }
262
263 .btn-primary {
264 background: #1a73e8;
265 color: white;
266 }
267
268 .btn-primary:hover {
269 background: #1557b0;
270 transform: translateY(-2px);
271 box-shadow: 0 4px 12px rgba(26, 115, 232, 0.4);
272 }
273
274 .btn-apple {
275 background: #000;
276 color: white;
277 }
278
279 .btn-apple:hover {
280 background: #333;
281 transform: translateY(-2px);
282 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
283 }
284
285 .btn:active {
286 transform: translateY(0);
287 }
288
289 .btn-secondary {
290 background: #6c757d;
291 color: white;
292 }
293
294 .btn-secondary:hover {
295 background: #5a6268;
296 transform: translateY(-2px);
297 box-shadow: 0 4px 12px rgba(108, 117, 125, 0.4);
298 }
299
300 .environment-toggle {
301 display: flex;
302 flex-direction: column;
303 gap: 0.5rem;
304 align-items: center;
305 padding-bottom: 1rem;
306 border-bottom: 1px solid rgba(255, 255, 255, 0.1);
307 margin-bottom: 1rem;
308 }
309
310 .environment-url {
311 font-size: 0.875rem;
312 color: #888;
313 margin: 0;
314 }
315
316 .btn-success {
317 background: #28a745;
318 color: white;
319 }
320
321 .btn-success:hover {
322 background: #218838;
323 transform: translateY(-2px);
324 box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4);
325 }
326
327 .btn-warning {
328 background: #ffc107;
329 color: #000;
330 }
331
332 .btn-warning:hover {
333 background: #e0a800;
334 transform: translateY(-2px);
335 box-shadow: 0 4px 12px rgba(255, 193, 7, 0.4);
336 }
337
338 .btn-danger {
339 background: #dc3545;
340 color: white;
341 }
342
343 .btn-danger:hover {
344 background: #c82333;
345 transform: translateY(-2px);
346 box-shadow: 0 4px 12px rgba(220, 53, 69, 0.4);
347 }
348 </style>