first commit

This commit is contained in:
AyrisAI
2026-08-20 01:51:59 +03:00
commit 97b83c7fd4
109 changed files with 21215 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
const KEY = "menulio.active-restaurant";
export interface ActiveRestaurant {
restaurantId: string;
locationId: string;
menuId: string;
slug: string;
}
export async function getActiveRestaurant(): Promise<ActiveRestaurant | null> {
const raw = await AsyncStorage.getItem(KEY);
return raw ? (JSON.parse(raw) as ActiveRestaurant) : null;
}
export async function setActiveRestaurant(value: ActiveRestaurant): Promise<void> {
await AsyncStorage.setItem(KEY, JSON.stringify(value));
}
export async function clearActiveRestaurant(): Promise<void> {
await AsyncStorage.removeItem(KEY);
}
+23
View File
@@ -0,0 +1,23 @@
import type { AiImportResponse, AiExtractedCategory } from "@menulio/shared";
let currentImportData: AiImportResponse | null = null;
export const aiStore = {
setImportData: (data: AiImportResponse) => {
currentImportData = data;
},
getImportData: (): AiImportResponse | null => {
return currentImportData;
},
updateCategories: (categories: AiExtractedCategory[]) => {
if (currentImportData) {
currentImportData = {
...currentImportData,
categories,
};
}
},
clear: () => {
currentImportData = null;
},
};
+36
View File
@@ -0,0 +1,36 @@
import { supabase } from "./supabase";
const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3001";
async function authHeaders(): Promise<Record<string, string>> {
const { data } = await supabase.auth.getSession();
const token = data.session?.access_token;
return {
"Content-Type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
};
}
async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
const headers = await authHeaders();
const res = await fetch(`${API_URL}${path}`, { ...options, headers });
if (!res.ok) {
const body = await res.json().catch(() => ({ message: res.statusText }));
throw new Error(body.message ?? `Request failed: ${res.status}`);
}
if (res.status === 204) return undefined as T;
return res.json() as Promise<T>;
}
export const api = {
get: <T>(path: string) => request<T>(path),
post: <T>(path: string, body?: unknown) =>
request<T>(path, { method: "POST", body: body ? JSON.stringify(body) : undefined }),
put: <T>(path: string, body?: unknown) =>
request<T>(path, { method: "PUT", body: body ? JSON.stringify(body) : undefined }),
patch: <T>(path: string, body: unknown) =>
request<T>(path, { method: "PATCH", body: JSON.stringify(body) }),
delete: <T>(path: string) => request<T>(path, { method: "DELETE" }),
};
+19
View File
@@ -0,0 +1,19 @@
import "react-native-url-polyfill/auto";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { createClient } from "@supabase/supabase-js";
const url = process.env.EXPO_PUBLIC_SUPABASE_URL;
const anonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
if (!url || !anonKey) {
throw new Error("EXPO_PUBLIC_SUPABASE_URL / EXPO_PUBLIC_SUPABASE_ANON_KEY missing");
}
export const supabase = createClient(url, anonKey, {
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
});
+15
View File
@@ -0,0 +1,15 @@
const WEB_BASE_URL = process.env.EXPO_PUBLIC_WEB_URL || "http://localhost:3000";
export function getPublicMenuUrl(slug: string): string {
if (WEB_BASE_URL.includes("menul.io")) {
return `https://${slug}.menul.io`;
}
return `${WEB_BASE_URL}/menu/${slug}`;
}
export function getPublicMenuDisplayUrl(slug: string): string {
if (WEB_BASE_URL.includes("menul.io")) {
return `${slug}.menul.io`;
}
return `${WEB_BASE_URL.replace(/^https?:\/\//, "")}/menu/${slug}`;
}