diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..d3cac01 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,15 @@ +version: 2 +updates: + - package-ecosystem: 'npm' + directory: '/' + schedule: + interval: 'monthly' + groups: + patch-dependencies: + update-types: + - 'patch' + + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'monthly' diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml new file mode 100644 index 0000000..77352a4 --- /dev/null +++ b/.github/workflows/CI.yaml @@ -0,0 +1,25 @@ +name: CI + +on: + push: + branches: + - "*" + pull_request: + branches: + - "*" + +jobs: + format: + name: Assert code formatting + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + - name: Install dependencies + run: cd mobile-app; npm install + - name: Run format check + run: cd mobile-app; npm run ci:format diff --git a/1 b/1 new file mode 100644 index 0000000..8ac6616 --- /dev/null +++ b/1 @@ -0,0 +1,6 @@ +Merge remote-tracking branch 'origin/react-query-setup' into new-ui +# Please enter a commit message to explain why this merge is necessary, +# especially if it merges an updated upstream into a topic branch. +# +# Lines starting with '#' will be ignored, and an empty message aborts +# the commit. diff --git a/mobile-app/.eslintrc.js b/mobile-app/.eslintrc.js new file mode 100644 index 0000000..7b96f57 --- /dev/null +++ b/mobile-app/.eslintrc.js @@ -0,0 +1,4 @@ +// https://docs.expo.dev/guides/using-eslint/ +module.exports = { + extends: 'expo', +}; diff --git a/mobile-app/.prettierrc.cjs b/mobile-app/.prettierrc.cjs new file mode 100644 index 0000000..428842a --- /dev/null +++ b/mobile-app/.prettierrc.cjs @@ -0,0 +1,15 @@ +// eslint-disable-next-line +module.exports = { + semi: true, + singleQuote: true, + trailingComma: 'es5', + printWidth: 80, + tabWidth: 4, + useTabs: false, + plugins: ['@trivago/prettier-plugin-sort-imports'], + importOrder: ['', '^@/(.*)$', '^[./]'], + importOrderSeparation: true, + importOrderSortSpecifiers: true, + importOrderGroupNamespaceSpecifiers: true, + importOrderCaseInsensitive: true, +}; diff --git a/mobile-app/README.md b/mobile-app/README.md index cd4feb8..60b2809 100644 --- a/mobile-app/README.md +++ b/mobile-app/README.md @@ -6,22 +6,22 @@ This is an [Expo](https://expo.dev) project created with [`create-expo-app`](htt 1. Install dependencies - ```bash - npm install - ``` + ```bash + npm install + ``` 2. Start the app - ```bash - npx expo start - ``` + ```bash + npx expo start + ``` In the output, you'll find options to open the app in a -- [development build](https://docs.expo.dev/develop/development-builds/introduction/) -- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/) -- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/) -- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo +- [development build](https://docs.expo.dev/develop/development-builds/introduction/) +- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/) +- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/) +- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction). @@ -39,12 +39,12 @@ This command will move the starter code to the **app-example** directory and cre To learn more about developing your project with Expo, look at the following resources: -- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides). -- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web. +- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides). +- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web. ## Join the community Join our community of developers creating universal apps. -- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute. -- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions. +- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute. +- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions. diff --git a/mobile-app/api/calls/group/groupHooks.ts b/mobile-app/api/calls/group/groupHooks.ts new file mode 100644 index 0000000..9f1dd1b --- /dev/null +++ b/mobile-app/api/calls/group/groupHooks.ts @@ -0,0 +1,18 @@ +import { useQuery } from 'react-query'; + +import { ApiId } from '@/api/types'; +import { createApi } from '@/api/utils/create-api'; + +interface IGroup { + id: ApiId; + name: string; +} + +export const useGroup = (id: ApiId) => { + const api = createApi(); + + return useQuery(['group', id], async () => { + const { data } = await api.get(`/groups/${id}`); + return data; + }); +}; diff --git a/mobile-app/api/hooks/groupHooks.ts b/mobile-app/api/hooks/groupHooks.ts new file mode 100644 index 0000000..27f8e64 --- /dev/null +++ b/mobile-app/api/hooks/groupHooks.ts @@ -0,0 +1,23 @@ +import { GroupSettingsProps } from '@/components/screens/GroupSettings'; + +import { useGroup } from '../calls/group/groupHooks'; +import { ApiId } from '../types'; + +export const useGroupSettingsProps = (groupId: ApiId) => { + const { data, ...props } = useGroup(groupId); + + const groupPageProps: GroupSettingsProps | null = data + ? { + groupName: data.name, + hasPremium: false, + pastSeasons: 0, + pushNotificationsEnabled: true, + groupCode: '123456', + } + : null; + + return { + props: groupPageProps, + ...props, + }; +}; diff --git a/mobile-app/api/types.ts b/mobile-app/api/types.ts new file mode 100644 index 0000000..661a69c --- /dev/null +++ b/mobile-app/api/types.ts @@ -0,0 +1 @@ +export type ApiId = string; diff --git a/mobile-app/api/utils/client.ts b/mobile-app/api/utils/client.ts new file mode 100644 index 0000000..e69de29 diff --git a/mobile-app/api/utils/create-api.ts b/mobile-app/api/utils/create-api.ts new file mode 100644 index 0000000..21aaecc --- /dev/null +++ b/mobile-app/api/utils/create-api.ts @@ -0,0 +1,14 @@ +import axios from 'axios'; + +// Might make sense to make a hook for this if we implment tokens and add a interceptor + +export const createApi = () => { + const api = axios.create({ + baseURL: process.env.API_BASE_URL, + headers: { + 'Content-Type': 'application/json', + }, + }); + + return api; +}; diff --git a/mobile-app/api/utils/query-client.ts b/mobile-app/api/utils/query-client.ts new file mode 100644 index 0000000..ba957c1 --- /dev/null +++ b/mobile-app/api/utils/query-client.ts @@ -0,0 +1,21 @@ +import { QueryClient } from 'react-query'; + +import { minutes } from '@/utils/time'; + +// --- QUERY CLIENT --- + +export const createQueryClient = () => { + const qc = new QueryClient(); + + qc.setDefaultOptions({ + queries: { + staleTime: minutes(2), + retry: false, + }, + mutations: { + retry: false, + }, + }); + + return qc; +}; diff --git a/mobile-app/app.json b/mobile-app/app.json index d3490bd..fc28c95 100644 --- a/mobile-app/app.json +++ b/mobile-app/app.json @@ -1,44 +1,44 @@ { - "expo": { - "name": "mobile-app", - "slug": "mobile-app", - "version": "1.0.0", - "orientation": "portrait", - "icon": "./assets/images/icon.png", - "scheme": "myapp", - "userInterfaceStyle": "automatic", - "splash": { - "image": "./assets/images/splash.png", - "resizeMode": "contain", - "backgroundColor": "#ffffff" - }, - "ios": { - "supportsTablet": true, - "bundleIdentifier": "com.linusbolls.mobileapp", + "expo": { + "name": "mobile-app", + "slug": "mobile-app", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/images/icon.png", + "scheme": "myapp", + "userInterfaceStyle": "automatic", + "splash": { + "image": "./assets/images/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "ios": { + "supportsTablet": true, + "bundleIdentifier": "com.linusbolls.mobileapp", - "infoPlist": { - "NSPhotoLibraryUsageDescription": true - } - }, - "android": { - "adaptiveIcon": { - "foregroundImage": "./assets/images/adaptive-icon.png", - "backgroundColor": "#ffffff" - } - }, - "web": { - "bundler": "metro", - "output": "static", - "favicon": "./assets/images/favicon.png" - }, - "plugins": ["expo-router"], - "experiments": { - "typedRoutes": true - }, - "extra": { - "eas": { - "projectId": "8dbfe974-43ce-4f4e-b3d8-cf6f77109412" - } + "infoPlist": { + "NSPhotoLibraryUsageDescription": true + } + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/images/adaptive-icon.png", + "backgroundColor": "#ffffff" + } + }, + "web": { + "bundler": "metro", + "output": "static", + "favicon": "./assets/images/favicon.png" + }, + "plugins": ["expo-router"], + "experiments": { + "typedRoutes": true + }, + "extra": { + "eas": { + "projectId": "8dbfe974-43ce-4f4e-b3d8-cf6f77109412" + } + } } - } } diff --git a/mobile-app/app/(tabs)/_layout.tsx b/mobile-app/app/(tabs)/_layout.tsx index e86361c..cb4501f 100644 --- a/mobile-app/app/(tabs)/_layout.tsx +++ b/mobile-app/app/(tabs)/_layout.tsx @@ -1,46 +1,46 @@ -import { Tabs } from "expo-router"; -import { TouchableOpacity } from "react-native"; -import React from "react"; -import Icon from "react-native-vector-icons/MaterialCommunityIcons"; +import { Tabs } from 'expo-router'; +import React from 'react'; +import { TouchableOpacity } from 'react-native'; +import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; -import { Colors } from "@/constants/Colors"; -import { useColorScheme } from "@/hooks/useColorScheme"; -import { ThemedText } from "@/components/ThemedText"; -import { theme } from "@/theme"; +import { ThemedText } from '@/components/ThemedText'; +import { Colors } from '@/constants/Colors'; +import { useColorScheme } from '@/hooks/useColorScheme'; +import { theme } from '@/theme'; export function HeaderItem({ - children, - noMargin = false, - onPress, - disabled = false, + children, + noMargin = false, + onPress, + disabled = false, }: { - children: string; - noMargin?: boolean; + children: string; + noMargin?: boolean; - onPress?: () => void; + onPress?: () => void; - disabled?: boolean; + disabled?: boolean; }) { - return ( - <> - - + + - {children} - - - {/*