diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..da947cf --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules +package.json +.eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..9d36119 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,26 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: ['plugin:react/recommended'], + parser: '@typescript-eslint/parser', + root: true, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 'latest', + sourceType: 'module', + }, + + plugins: ['react-native', 'jest', 'simple-import-sort', '@typescript-eslint'], + rules: { + "@typescript-eslint/method-signature-style": [ + "error", + "property" + ], + 'react/react-in-jsx-scope': 'off', + 'react/no-unescaped-entities': 'off', + }, +}; diff --git a/.gitignore b/.gitignore index 05647d5..0b37b6e 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,9 @@ yarn-error.* # typescript *.tsbuildinfo + +# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb +# The following patterns were generated by expo-cli + +expo-env.d.ts +# @end expo-cli \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..deaaa98 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,40 @@ +image: node:20 + +stages: + - install + - lint + - test + +cache: + paths: + - node_modules/ + +before_script: + - npm install + - apt-get update + +install_dependencies: + stage: install + script: + - npm install + artifacts: + paths: + - node_modules/ + expire_in: 1 week + +lint: + stage: test + script: + - npm run lint + - npm run types + only: + - branches + - merge_requests + +test: + stage: test + script: + - npm test + only: + - branches + - merge_requests diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100644 index 0000000..31e0db2 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1 @@ +npm run types && npm run lint diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx deleted file mode 100644 index 30914fb..0000000 --- a/app/(tabs)/_layout.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import FontAwesome from '@expo/vector-icons/FontAwesome'; -import { Link, Tabs } from 'expo-router'; -import { Pressable } from 'react-native'; - -import Colors from '@/constants/Colors'; -import { useColorScheme } from '@/components/useColorScheme'; -import { useClientOnlyValue } from '@/components/useClientOnlyValue'; - -// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/ -function TabBarIcon(props: { - name: React.ComponentProps['name']; - color: string; -}) { - return ; -} - -export default function TabLayout() { - const colorScheme = useColorScheme(); - - return ( - - , - headerRight: () => ( - - - {({ pressed }) => ( - - )} - - - ), - }} - /> - , - }} - /> - - ); -} diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx deleted file mode 100644 index 6cbee6d..0000000 --- a/app/(tabs)/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { StyleSheet } from 'react-native'; - -import EditScreenInfo from '@/components/EditScreenInfo'; -import { Text, View } from '@/components/Themed'; - -export default function TabOneScreen() { - return ( - - Tab One - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - title: { - fontSize: 20, - fontWeight: 'bold', - }, - separator: { - marginVertical: 30, - height: 1, - width: '80%', - }, -}); diff --git a/app/(tabs)/two.tsx b/app/(tabs)/two.tsx deleted file mode 100644 index f2ea47e..0000000 --- a/app/(tabs)/two.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { StyleSheet } from 'react-native'; - -import EditScreenInfo from '@/components/EditScreenInfo'; -import { Text, View } from '@/components/Themed'; - -export default function TabTwoScreen() { - return ( - - Tab Two - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - title: { - fontSize: 20, - fontWeight: 'bold', - }, - separator: { - marginVertical: 30, - height: 1, - width: '80%', - }, -}); diff --git a/app/+not-found.tsx b/app/+not-found.tsx index ffb5643..45c0b68 100644 --- a/app/+not-found.tsx +++ b/app/+not-found.tsx @@ -1,7 +1,7 @@ import { Link, Stack } from 'expo-router'; import { StyleSheet } from 'react-native'; -import { Text, View } from '@/components/Themed'; +import { Text, View } from '@/components/shared/Themed'; export default function NotFoundScreen() { return ( @@ -9,10 +9,6 @@ export default function NotFoundScreen() { This screen doesn't exist. - - - Go to home screen! - ); diff --git a/app/RootStackParamList.ts b/app/RootStackParamList.ts new file mode 100644 index 0000000..309d108 --- /dev/null +++ b/app/RootStackParamList.ts @@ -0,0 +1,4 @@ +export type RootStackParamList = { + dashboard: undefined; + timer: { reps: number, restTime: number, workTime: number}; +}; diff --git a/app/_layout.tsx b/app/_layout.tsx index 40cdc48..3a7f1ad 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,13 +1,12 @@ import FontAwesome from '@expo/vector-icons/FontAwesome'; -import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; +import { ThemeProvider } from '@emotion/react'; +import { theme } from '@/app/shared/theme'; import { useFonts } from 'expo-font'; import { Stack } from 'expo-router'; import * as SplashScreen from 'expo-splash-screen'; import { useEffect } from 'react'; import 'react-native-reanimated'; -import { useColorScheme } from '@/components/useColorScheme'; - export { // Catch any errors thrown by the Layout component. ErrorBoundary, @@ -15,7 +14,7 @@ export { export const unstable_settings = { // Ensure that reloading on `/modal` keeps a back button present. - initialRouteName: '(tabs)', + initialRouteName: 'dashboard', }; // Prevent the splash screen from auto-hiding before asset loading is complete. @@ -46,13 +45,11 @@ export default function RootLayout() { } function RootLayoutNav() { - const colorScheme = useColorScheme(); - return ( - + - - + + ); diff --git a/app/dashboard.tsx b/app/dashboard.tsx new file mode 100644 index 0000000..47d8e76 --- /dev/null +++ b/app/dashboard.tsx @@ -0,0 +1,134 @@ +import React, { useState } from 'react'; + +import { Text } from '@/components/shared/Themed'; +import Card from '@/components/shared/Card'; +import styled from '@emotion/native'; +import { formatTime } from '@/components/shared/business/timeHelpers'; +import { useNavigation } from '@react-navigation/native'; +import { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { RootStackParamList } from '@/app/RootStackParamList'; +import { VerticalSpacer } from '@/components/shared/Spacers'; +import { TimerPickerModal } from 'react-native-timer-picker'; +import Button from '@/components/shared/Button'; +import NumberSelector from '@/components/shared/NumberSelector'; + +type NavigationProp = NativeStackNavigationProp; + +export default function Dashboard() { + const navigation = useNavigation(); + + const [reps, setReps] = useState(1); + const [workTime, setWorkTime] = useState(0); + const [restTime, setRestTime] = useState(0); + const [showWorkTimePicker, setShowWorkTimePicker] = useState(false); + const [showRestTimePicker, setShowRestTimePicker] = useState(false); + + const totalWorkTime: string = formatTime((workTime + restTime) * reps); + + return ( + + Boxons + + + + + + + Reps. + + + + + setShowWorkTimePicker(true)}> + + Fight + {formatTime(workTime)} + + + + { + setWorkTime(pickedDuration.minutes * 60 + pickedDuration.seconds); + setShowWorkTimePicker(false); + }} + modalTitle="Set Round Time" + onCancel={() => setShowWorkTimePicker(false)} + closeOnOverlayPress + styles={{ + theme: "dark", + }} + modalProps={{ + overlayOpacity: 0.2, + }} + /> + + setShowRestTimePicker(true)}> + + Repos + {formatTime(restTime)} + + + + { + setRestTime(pickedDuration.minutes * 60 + pickedDuration.seconds); + setShowRestTimePicker(false); + }} + modalTitle="Set Rest Time" + onCancel={() => setShowRestTimePicker(false)} + closeOnOverlayPress + styles={{ + theme: "dark", + }} + modalProps={{ + overlayOpacity: 0.2, + }} + /> + + + + Temps total de travail : {totalWorkTime} + + + +