/ widget-task-handler.ts
widget-task-handler.ts
  1  import React from "react";
  2  import type { WidgetTaskHandlerProps } from "react-native-android-widget";
  3  import { ImageWidget } from "./components/image-widget";
  4  import { AuthStorage } from "./utils/auth-storage";
  5  import { ConvexHttpClient } from "convex/browser";
  6  import { api } from "./convex/_generated/api";
  7  import { getCachedImage, cacheImage } from "./utils/image-cache";
  8  
  9  async function getClerkAuthToken(): Promise<string | null> {
 10  	try {
 11  		const storedToken = await AuthStorage.getToken();
 12  		if (storedToken) return storedToken;
 13  		console.warn("No Clerk auth token found in storage");
 14  		return null;
 15  	} catch (error) {
 16  		console.error("Failed to get Clerk auth token:", error);
 17  		return null;
 18  	}
 19  }
 20  
 21  async function fetchLatestDrawing(): Promise<string | null> {
 22  	try {
 23  		console.log("Fetching latest drawing for widget update...");
 24  
 25  		const convexUrl = process.env.EXPO_PUBLIC_CONVEX_URL;
 26  		if (!convexUrl) {
 27  			console.error("EXPO_PUBLIC_CONVEX_URL is not defined.");
 28  			return await getCachedImage();
 29  		}
 30  
 31  		const client = new ConvexHttpClient(convexUrl);
 32  
 33  		const authToken = await getClerkAuthToken();
 34  		if (!authToken) {
 35  			console.warn("No auth token available, trying cached image...");
 36  			return await getCachedImage();
 37  		}
 38  		client.setAuth(authToken);
 39  
 40  		const result = await client.query(api.drawings.getDrawings, {
 41  			pairDrawingsOnly: true,
 42  			limit: 1,
 43  		});
 44  
 45  		if (result && result.length > 0 && result[0].imageUrl) {
 46  			const imageUrl = result[0].imageUrl;
 47  			cacheImage(imageUrl).catch((error) => {
 48  				console.error("Failed to cache image:", error);
 49  			});
 50  			return imageUrl;
 51  		}
 52  
 53  		console.log("No drawings found, trying cached image...");
 54  		return await getCachedImage();
 55  	} catch (error) {
 56  		console.error("Failed to fetch latest drawing:", error);
 57  		return await getCachedImage();
 58  	}
 59  }
 60  
 61  const nameToWidget = {
 62  	Liontin: ImageWidget,
 63  };
 64  
 65  export async function widgetTaskHandler(props: WidgetTaskHandlerProps) {
 66  	const widgetInfo = props.widgetInfo;
 67  	const Widget =
 68  		nameToWidget[widgetInfo.widgetName as keyof typeof nameToWidget];
 69  
 70  	switch (props.widgetAction) {
 71  		case "WIDGET_ADDED": {
 72  			console.log("Widget added, fetching initial data...");
 73  			const imageUrl = await fetchLatestDrawing();
 74  			props.renderWidget(
 75  				React.createElement(Widget, {
 76  					imageUrl,
 77  					width: 180,
 78  				}),
 79  			);
 80  			break;
 81  		}
 82  
 83  		case "WIDGET_CLICK":
 84  		case "WIDGET_UPDATE": {
 85  			console.log("Widget update triggered, fetching latest drawing...");
 86  			const imageUrl = await fetchLatestDrawing();
 87  			props.renderWidget(React.createElement(Widget, { imageUrl, width: 180 }));
 88  			break;
 89  		}
 90  
 91  		case "WIDGET_RESIZED": {
 92  			console.log("Widget resized, re-rendering...");
 93  			const imageUrl = await fetchLatestDrawing();
 94  			props.renderWidget(
 95  				React.createElement(Widget, {
 96  					imageUrl,
 97  					width: 180,
 98  				}),
 99  			);
100  			break;
101  		}
102  
103  		case "WIDGET_DELETED":
104  			console.log("Widget deleted");
105  			break;
106  
107  		default:
108  			break;
109  	}
110  }