diff --git a/apps/expo/.env.example b/apps/expo/.env.example
deleted file mode 100644
index 696c592..0000000
--- a/apps/expo/.env.example
+++ /dev/null
@@ -1,2 +0,0 @@
-EXPO_PUBLIC_SUPABASE_URL="https://YOUR_PROJECT_REF.supabase.co"
-EXPO_PUBLIC_SUPABASE_ANON_KEY="YOUR_ANON_KEY"
diff --git a/apps/expo/.expo-shared/assets.json b/apps/expo/.expo-shared/assets.json
deleted file mode 100644
index 1e6decf..0000000
--- a/apps/expo/.expo-shared/assets.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
- "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
-}
diff --git a/apps/expo/app.config.ts b/apps/expo/app.config.ts
deleted file mode 100644
index 98cd68b..0000000
--- a/apps/expo/app.config.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import type { ConfigContext, ExpoConfig } from "@expo/config";
-
-if (
- !process.env.EXPO_PUBLIC_SUPABASE_URL ||
- !process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY
-) {
- throw new Error(
- "Please provide SUPABASE_URL and SUPABASE_ANON_KEY in your .env file",
- );
-}
-
-export default ({ config }: ConfigContext): ExpoConfig => ({
- ...config,
- name: "expo",
- slug: "expo",
- scheme: "expo",
- version: "0.1.0",
- orientation: "portrait",
- icon: "./assets/icon.png",
- userInterfaceStyle: "automatic",
- splash: {
- image: "./assets/icon.png",
- resizeMode: "contain",
- backgroundColor: "#18181A",
- },
- updates: {
- fallbackToCacheTimeout: 0,
- },
- assetBundlePatterns: ["**/*"],
- ios: {
- bundleIdentifier: "your.bundle.identifier",
- supportsTablet: true,
- usesAppleSignIn: true,
- config: {
- usesNonExemptEncryption: false,
- },
- },
- android: {
- package: "your.bundle.identifier",
- adaptiveIcon: {
- foregroundImage: "./assets/icon.png",
- backgroundColor: "#18181A",
- },
- },
- experiments: {
- tsconfigPaths: true,
- typedRoutes: true,
- },
- // extra: {
- // eas: {
- // projectId: "your-project-id",
- // },
- // },
- plugins: ["expo-router", "expo-secure-store", "expo-apple-authentication"],
-});
diff --git a/apps/expo/assets/icon-dark.png b/apps/expo/assets/icon-dark.png
deleted file mode 100644
index 2160300..0000000
Binary files a/apps/expo/assets/icon-dark.png and /dev/null differ
diff --git a/apps/expo/assets/icon.png b/apps/expo/assets/icon.png
deleted file mode 100644
index 871bf7b..0000000
Binary files a/apps/expo/assets/icon.png and /dev/null differ
diff --git a/apps/expo/babel.config.js b/apps/expo/babel.config.js
deleted file mode 100644
index 95b1393..0000000
--- a/apps/expo/babel.config.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/** @type {import("@babel/core").ConfigFunction} */
-module.exports = (api) => {
- api.cache(true);
- return {
- presets: [
- ["babel-preset-expo", { jsxImportSource: "nativewind" }],
- "nativewind/babel",
- ],
- plugins: ["react-native-reanimated/plugin"],
- };
-};
diff --git a/apps/expo/eas.json b/apps/expo/eas.json
deleted file mode 100644
index 607de32..0000000
--- a/apps/expo/eas.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "cli": {
- "version": ">= 4.1.2"
- },
- "build": {
- "base": {
- "node": "18.16.1",
- "ios": {
- "resourceClass": "m-medium"
- }
- },
- "development": {
- "extends": "base",
- "developmentClient": true,
- "distribution": "internal"
- },
- "preview": {
- "extends": "base",
- "distribution": "internal",
- "ios": {
- "simulator": true
- }
- },
- "production": {
- "extends": "base"
- }
- },
- "submit": {
- "production": {}
- }
-}
diff --git a/apps/expo/eslint.config.mjs b/apps/expo/eslint.config.mjs
deleted file mode 100644
index 74b9306..0000000
--- a/apps/expo/eslint.config.mjs
+++ /dev/null
@@ -1,11 +0,0 @@
-import baseConfig from "@wellchart/eslint-config/base";
-import reactConfig from "@wellchart/eslint-config/react";
-
-/** @type {import('typescript-eslint').Config} */
-export default [
- {
- ignores: [".expo/**", "expo-plugins/**"],
- },
- ...baseConfig,
- ...reactConfig,
-];
diff --git a/apps/expo/index.ts b/apps/expo/index.ts
deleted file mode 100644
index 80d3d99..0000000
--- a/apps/expo/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-import "expo-router/entry";
diff --git a/apps/expo/metro.config.js b/apps/expo/metro.config.js
deleted file mode 100644
index 4944183..0000000
--- a/apps/expo/metro.config.js
+++ /dev/null
@@ -1,55 +0,0 @@
-// Learn more: https://docs.expo.dev/guides/monorepos/
-const { getDefaultConfig } = require("expo/metro-config");
-const { FileStore } = require("metro-cache");
-const { withNativeWind } = require("nativewind/metro");
-
-const path = require("path");
-
-module.exports = withTurborepoManagedCache(
- withMonorepoPaths(
- withNativeWind(getDefaultConfig(__dirname), {
- input: "./src/styles.css",
- configPath: "./tailwind.config.ts",
- }),
- ),
-);
-
-/**
- * Add the monorepo paths to the Metro config.
- * This allows Metro to resolve modules from the monorepo.
- *
- * @see https://docs.expo.dev/guides/monorepos/#modify-the-metro-config
- * @param {import('expo/metro-config').MetroConfig} config
- * @returns {import('expo/metro-config').MetroConfig}
- */
-function withMonorepoPaths(config) {
- const projectRoot = __dirname;
- const workspaceRoot = path.resolve(projectRoot, "../..");
-
- // #1 - Watch all files in the monorepo
- config.watchFolders = [workspaceRoot];
-
- // #2 - Resolve modules within the project's `node_modules` first, then all monorepo modules
- config.resolver.nodeModulesPaths = [
- path.resolve(projectRoot, "node_modules"),
- path.resolve(workspaceRoot, "node_modules"),
- ];
-
- return config;
-}
-
-/**
- * Move the Metro cache to the `node_modules/.cache/metro` folder.
- * This repository configured Turborepo to use this cache location as well.
- * If you have any environment variables, you can configure Turborepo to invalidate it when needed.
- *
- * @see https://turbo.build/repo/docs/reference/configuration#env
- * @param {import('expo/metro-config').MetroConfig} config
- * @returns {import('expo/metro-config').MetroConfig}
- */
-function withTurborepoManagedCache(config) {
- config.cacheStores = [
- new FileStore({ root: path.join(__dirname, "node_modules/.cache/metro") }),
- ];
- return config;
-}
diff --git a/apps/expo/package.json b/apps/expo/package.json
deleted file mode 100644
index 90f9be3..0000000
--- a/apps/expo/package.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "name": "@wellchart/expo",
- "version": "0.1.0",
- "private": true,
- "main": "index.ts",
- "scripts": {
- "clean": "git clean -xdf .expo .turbo node_modules",
- "dev": "expo start",
- "dev:android": "expo start --android",
- "dev:ios": "expo start --ios",
- "android": "expo run:android",
- "ios": "expo run:ios",
- "format": "prettier --check . --ignore-path ../../.gitignore",
- "lint": "eslint",
- "typecheck": "tsc --noEmit"
- },
- "dependencies": {
- "@expo/metro-config": "^0.17.7",
- "@shopify/flash-list": "1.6.4",
- "@supabase/auth-helpers-react": "^0.4.2",
- "@supabase/supabase-js": "^2.43.1",
- "@tanstack/react-query": "^5.35.1",
- "@trpc/client": "11.0.0-rc.364",
- "@trpc/react-query": "11.0.0-rc.364",
- "@trpc/server": "11.0.0-rc.364",
- "expo": "~50.0.14",
- "expo-apple-authentication": "~6.3.0",
- "expo-constants": "~15.4.5",
- "expo-crypto": "~12.8.1",
- "expo-dev-client": "~3.3.11",
- "expo-image": "~1.10.6",
- "expo-linking": "~6.2.2",
- "expo-router": "~3.4.8",
- "expo-secure-store": "~12.8.1",
- "expo-splash-screen": "~0.26.4",
- "expo-status-bar": "~1.11.1",
- "nativewind": "~4.0.36",
- "react": "18.3.1",
- "react-dom": "18.3.1",
- "react-native": "~0.73.6",
- "react-native-css-interop": "~0.0.34",
- "react-native-gesture-handler": "~2.14.1",
- "react-native-reanimated": "~3.8.1",
- "react-native-safe-area-context": "~4.8.2",
- "react-native-screens": "~3.29.0",
- "react-native-url-polyfill": "^1.3.0",
- "superjson": "2.2.1"
- },
- "devDependencies": {
- "@wellchart/api": "workspace:*",
- "@wellchart/eslint-config": "workspace:*",
- "@wellchart/prettier-config": "workspace:*",
- "@wellchart/tailwind-config": "workspace:*",
- "@wellchart/tsconfig": "workspace:*",
- "@babel/core": "^7.24.5",
- "@babel/preset-env": "^7.24.5",
- "@babel/runtime": "^7.24.5",
- "@expo/config-plugins": "^7.9.1",
- "@types/babel__core": "^7.20.5",
- "@types/react": "^18.3.1",
- "eslint": "^9.2.0",
- "prettier": "^3.2.5",
- "tailwindcss": "^3.4.3",
- "typescript": "^5.4.5"
- },
- "prettier": "@wellchart/prettier-config"
-}
diff --git a/apps/expo/src/app/_layout.tsx b/apps/expo/src/app/_layout.tsx
deleted file mode 100644
index 99c881d..0000000
--- a/apps/expo/src/app/_layout.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Stack } from "expo-router";
-import { StatusBar } from "expo-status-bar";
-import { SessionContextProvider } from "@supabase/auth-helpers-react";
-
-import { HeaderBackButton, HeaderTitle } from "~/components/header";
-import { TRPCProvider } from "~/utils/api";
-import { supabase } from "~/utils/supabase";
-
-import "../styles.css";
-
-import { useColorScheme } from "nativewind";
-
-// This is the main layout of the app
-// It wraps your pages with the providers they need
-export default function RootLayout() {
- const { colorScheme } = useColorScheme();
- return (
-
-
- {/*
- * The Stack component displays the current page.
- * It also allows you to configure your screens
- */}
-
- {/*
- * Present the profile screen as a modal
- * @see https://expo.github.io/router/docs/guides/modals
- */}
- <>>,
- }}
- />
-
-
-
-
- );
-}
diff --git a/apps/expo/src/app/index.tsx b/apps/expo/src/app/index.tsx
deleted file mode 100644
index c3350a7..0000000
--- a/apps/expo/src/app/index.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-import React from "react";
-import {
- Alert,
- Keyboard,
- KeyboardAvoidingView,
- Platform,
- Pressable,
- Text,
- TextInput,
- TouchableWithoutFeedback,
- View,
-} from "react-native";
-import { SafeAreaView } from "react-native-safe-area-context";
-import { Image } from "expo-image";
-import { Link, Stack } from "expo-router";
-import { FlashList } from "@shopify/flash-list";
-
-import type { RouterOutputs } from "~/utils/api";
-import { AuthAvatar } from "~/components/header";
-import { api } from "~/utils/api";
-
-function PostCard(props: { post: RouterOutputs["post"]["all"][number] }) {
- const { post } = props;
-
- const utils = api.useUtils();
-
- const { mutate: deletePost } = api.post.delete.useMutation({
- onSettled: () => utils.post.all.invalidate(),
- onError: (error) => {
- if (error.data?.code === "UNAUTHORIZED")
- Alert.alert("Error", "Only the author can delete their post");
- },
- });
-
- return (
-
-
-
-
-
-
-
- {post.title}
-
- {post.content}
-
-
-
-
- deletePost(post.id)}>
- Delete
-
-
- );
-}
-
-function CreatePost() {
- const utils = api.useUtils();
-
- const [title, setTitle] = React.useState("");
- const [content, setContent] = React.useState("");
-
- const { mutate: createPost, error } = api.post.create.useMutation({
- onSuccess: async () => {
- setTitle("");
- setContent("");
- Keyboard.dismiss();
- await utils.post.all.invalidate();
- },
- onError: (error) => {
- if (error.data?.code === "UNAUTHORIZED")
- Alert.alert("Error", "You must be logged in to create a post");
- },
- });
-
- return (
-
-
-
-
- {error?.data?.zodError?.fieldErrors.title && (
-
- {error.data.zodError.fieldErrors.title}
-
- )}
-
- {error?.data?.zodError?.fieldErrors.content && (
-
- {error.data.zodError.fieldErrors.content}
-
- )}
- {
- createPost({
- title,
- content,
- });
- }}
- >
- Publish post
-
-
-
-
- );
-}
-
-export default function HomeScreen() {
- const utils = api.useUtils();
-
- const postQuery = api.post.all.useQuery();
-
- return (
-
- ,
- headerTitle: () => (
-
- T3
- x
- Supabase
-
- ),
- }}
- />
-
- void utils.post.all.invalidate()}
- >
- Refresh posts
-
-
-
-
- Press on a post
-
-
-
- }
- renderItem={(p) => }
- />
-
-
-
-
- );
-}
diff --git a/apps/expo/src/app/post/[id].tsx b/apps/expo/src/app/post/[id].tsx
deleted file mode 100644
index d27136a..0000000
--- a/apps/expo/src/app/post/[id].tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { SafeAreaView, Text, View } from "react-native";
-import { Stack, useGlobalSearchParams } from "expo-router";
-
-import { api } from "~/utils/api";
-
-export default function Post() {
- const { id } = useGlobalSearchParams();
- if (!id || typeof id !== "string") throw new Error("unreachable");
- const { data } = api.post.byId.useQuery({ id });
-
- if (!data) return null;
-
- return (
-
-
-
-
- {data.title}
-
- {data.content}
-
-
- );
-}
diff --git a/apps/expo/src/app/profile.tsx b/apps/expo/src/app/profile.tsx
deleted file mode 100644
index 9342f47..0000000
--- a/apps/expo/src/app/profile.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-import { useState } from "react";
-import { Alert, Pressable, Text, TextInput, View } from "react-native";
-import * as AppleAuthentication from "expo-apple-authentication";
-import { AntDesign } from "@expo/vector-icons";
-import { useSupabaseClient, useUser } from "@supabase/auth-helpers-react";
-
-import { initiateAppleSignIn } from "~/utils/auth";
-
-export default function Profile() {
- const user = useUser();
- return (
-
- {user ? : }
-
- );
-}
-
-function SignedInView() {
- const supabase = useSupabaseClient();
- const user = useUser();
-
- return (
-
- Signed in as {user?.email}
- supabase.auth.signOut()}
- className="flex-row items-center justify-center gap-2 rounded-lg bg-zinc-200 p-2"
- >
- Sign out
-
-
- );
-}
-
-function SignedOutView() {
- const supabase = useSupabaseClient();
-
- const signInWithApple = async () => {
- try {
- const { token, nonce } = await initiateAppleSignIn();
- const { error } = await supabase.auth.signInWithIdToken({
- provider: "apple",
- token,
- nonce,
- });
- if (error) return Alert.alert("Error", error.message);
- } catch (e) {
- if (typeof e === "object" && !!e && "code" in e) {
- if (e.code === "ERR_REQUEST_CANCELED") {
- // handle that the user canceled the sign-in flow
- } else {
- // handle other errors
- }
- } else {
- console.error("Unexpected error from Apple SignIn: ", e);
- }
- }
- };
-
- return (
-
- Sign In
-
- {/* Email Sign In */}
-
-
-
-
- or
-
-
-
- {/* Sign in with Apple */}
-
-
- );
-}
-
-function EmailForm() {
- const supabase = useSupabaseClient();
-
- const [email, setEmail] = useState("");
- const [password, setPassword] = useState("");
- const [showPassword, setShowPassword] = useState(false);
- const [isSignUp, setIsSignUp] = useState(false);
-
- const signInWithPassword = async () => {
- const { error, data } = isSignUp
- ? await supabase.auth.signUp({
- email,
- password,
- })
- : await supabase.auth.signInWithPassword({
- email,
- password,
- });
- if (error) Alert.alert("Error", error.message);
- else if (isSignUp && data.user) {
- Alert.alert("Check your email for a confirmation link.");
- setIsSignUp(false);
- }
- };
-
- return (
-
-
-
-
- setShowPassword((prev) => !prev)}
- >
- {showPassword && }
- {!showPassword && }
-
-
-
- setIsSignUp((prev) => !prev)}>
-
- {isSignUp ? "Already have an account?" : "Don't have an account?"}
-
-
-
-
-
- {isSignUp ? "Sign Up" : "Sign In"}
-
-
-
- );
-}
diff --git a/apps/expo/src/components/header.tsx b/apps/expo/src/components/header.tsx
deleted file mode 100644
index 9a92a43..0000000
--- a/apps/expo/src/components/header.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import type { ReactNode } from "react";
-import { Button, Text, TouchableOpacity } from "react-native";
-import { useRouter } from "expo-router";
-import { Ionicons } from "@expo/vector-icons";
-
-export function AuthAvatar() {
- // const user = useUser();
- const router = useRouter();
- // const profileImage = user?.user_metadata.avatar_url as string | undefined;
-
- return