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