Skip to content

Commit

Permalink
Feat/task screen title block (#1674)
Browse files Browse the repository at this point in the history
* added task screen

* added the api to get task by id, and storing in in global state

* added the text input for title, also the icons necessary for editing, copying, saving

* added copy title func, refactored and fixed build error

* limited the title text to 255 chars max, showing a flash message when it's exceeded and title is being saved, also when title is copied

* updated color of copy title flash message
  • Loading branch information
desperado1802 authored Oct 28, 2023
1 parent a289156 commit 8f93c06
Show file tree
Hide file tree
Showing 22 changed files with 3,209 additions and 2,596 deletions.
72 changes: 37 additions & 35 deletions apps/mobile/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,63 +9,64 @@
* The app navigation resides in ./app/navigators, so head over there
* if you're interested in adding screens and navigators.
*/
import './i18n';
import './utils/ignoreWarnings';
import { useFonts } from 'expo-font';
import React, { useEffect } from 'react';
import { Provider as PaperProvider } from 'react-native-paper';
import "./i18n"
import "./utils/ignoreWarnings"
import { useFonts } from "expo-font"
import React, { useEffect } from "react"
import { Provider as PaperProvider } from "react-native-paper"

import { initialWindowMetrics, SafeAreaProvider } from 'react-native-safe-area-context';
import { useInitialRootStore, useStores } from './models';
import { AppNavigator, useNavigationPersistence } from './navigators';
import { ErrorBoundary } from './screens/ErrorScreen/ErrorBoundary';
import * as storage from './utils/storage';
import { customDarkTheme, customFontsToLoad, customLightTheme } from './theme';
import { setupReactotron } from './services/reactotron';
import Config from './config';
import { observer } from 'mobx-react-lite';
import { initCrashReporting } from './utils/crashReporting';
import { initialWindowMetrics, SafeAreaProvider } from "react-native-safe-area-context"
import { useInitialRootStore, useStores } from "./models"
import { AppNavigator, useNavigationPersistence } from "./navigators"
import { ErrorBoundary } from "./screens/ErrorScreen/ErrorBoundary"
import * as storage from "./utils/storage"
import { customDarkTheme, customFontsToLoad, customLightTheme } from "./theme"
import { setupReactotron } from "./services/reactotron"

Check warning on line 24 in apps/mobile/app/app.tsx

View workflow job for this annotation

GitHub Actions / Cspell

Unknown word (Reactotron)

Check warning on line 24 in apps/mobile/app/app.tsx

View workflow job for this annotation

GitHub Actions / Cspell

Unknown word (reactotron)
import Config from "./config"
import { observer } from "mobx-react-lite"
import { initCrashReporting } from "./utils/crashReporting"
import FlashMessage from "react-native-flash-message"

// Set up Reactotron, which is a free desktop app for inspecting and debugging

Check warning on line 30 in apps/mobile/app/app.tsx

View workflow job for this annotation

GitHub Actions / Cspell

Unknown word (Reactotron)
// React Native apps. Learn more here: https://github.com/infinitered/reactotron
setupReactotron({

Check warning on line 32 in apps/mobile/app/app.tsx

View workflow job for this annotation

GitHub Actions / Cspell

Unknown word (Reactotron)
// clear the Reactotron window when the app loads/reloads

Check warning on line 33 in apps/mobile/app/app.tsx

View workflow job for this annotation

GitHub Actions / Cspell

Unknown word (Reactotron)
clearOnLoad: true,
// generally going to be localhost
host: 'localhost',
host: "localhost",
// Reactotron can monitor AsyncStorage for you

Check warning on line 37 in apps/mobile/app/app.tsx

View workflow job for this annotation

GitHub Actions / Cspell

Unknown word (Reactotron)
useAsyncStorage: true,
// log the initial restored state from AsyncStorage
logInitialState: true,
// log out any snapshots as they happen (this is useful for debugging but slow)
logSnapshots: false
});
logSnapshots: false,
})

export const NAVIGATION_PERSISTENCE_KEY = 'NAVIGATION_STATE';
export const NAVIGATION_PERSISTENCE_KEY = "NAVIGATION_STATE"

interface AppProps {
hideSplashScreen: () => Promise<void>;
hideSplashScreen: () => Promise<void>
}

/**
* This is the root component of our app.
*/
const App = observer((props: AppProps) => {
const { hideSplashScreen } = props;
const { hideSplashScreen } = props
const {
initialNavigationState,
onNavigationStateChange,
isRestored: isNavigationStateRestored
} = useNavigationPersistence(storage, NAVIGATION_PERSISTENCE_KEY);
isRestored: isNavigationStateRestored,
} = useNavigationPersistence(storage, NAVIGATION_PERSISTENCE_KEY)
const {
authenticationStore: { isDarkMode }
} = useStores();
authenticationStore: { isDarkMode },
} = useStores()

useEffect(() => {
initCrashReporting(); // To initialize Sentry.io
}, []);
initCrashReporting() // To initialize Sentry.io
}, [])

const [areFontsLoaded] = useFonts(customFontsToLoad);
const [areFontsLoaded] = useFonts(customFontsToLoad)

const { rehydrated } = useInitialRootStore(() => {
// This runs after the root store has been initialized and rehydrated.
Expand All @@ -74,24 +75,25 @@ const App = observer((props: AppProps) => {
// Slightly delaying splash screen hiding for better UX; can be customized or removed as needed,
// Note: (vanilla Android) The splash-screen will not appear if you launch your app via the terminal or Android Studio. Kill the app and launch it normally by tapping on the launcher icon. https://stackoverflow.com/a/69831106
// Note: (vanilla iOS) You might notice the splash-screen logo change size. This happens in debug/development mode. Try building the app for release.
setTimeout(hideSplashScreen, 500);
});
setTimeout(hideSplashScreen, 500)
})

// Before we show the app, we have to wait for our state to be ready.
// In the meantime, don't render anything. This will be the background
// color set in native by rootView's background color.
// In iOS: application:didFinishLaunchingWithOptions:
// In Android: https://stackoverflow.com/a/45838109/204044
// You can replace with your own loading component if you wish.
if (!rehydrated || !isNavigationStateRestored || !areFontsLoaded) return null;
if (!rehydrated || !isNavigationStateRestored || !areFontsLoaded) return null

// otherwise, we're ready to render the app

const theme = isDarkMode ? customDarkTheme : customLightTheme;
const theme = isDarkMode ? customDarkTheme : customLightTheme
return (
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
<PaperProvider theme={theme}>
<ErrorBoundary catchErrors={Config.catchErrors}>
<FlashMessage position="top" />
<AppNavigator
theme={theme}
initialState={initialNavigationState}
Expand All @@ -100,6 +102,6 @@ const App = observer((props: AppProps) => {
</ErrorBoundary>
</PaperProvider>
</SafeAreaProvider>
);
});
export default App;
)
})
export default App
140 changes: 71 additions & 69 deletions apps/mobile/app/components/ProfileImage.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,60 @@
/* eslint-disable react-native/no-unused-styles */
/* eslint-disable react-native/no-color-literals */
/* eslint-disable react-native/no-inline-styles */
import React, { FC, useMemo } from 'react';
import { View, StyleSheet } from 'react-native';
import { Avatar } from 'react-native-paper';
import { IUser } from '../services/interfaces/IUserData';
import { typography, useAppTheme } from '../theme';
import { imgTitleProfileAvatar } from '../helpers/img-title-profile-avatar';
import { useOrganizationTeam } from '../services/hooks/useOrganization';
import { useTimer } from '../services/hooks/useTimer';
import { getTimerStatusValue } from '../helpers/get-timer-status';
import React, { FC, useMemo } from "react"
import { View, StyleSheet } from "react-native"
import { Avatar } from "react-native-paper"
import { IUser } from "../services/interfaces/IUserData"
import { typography, useAppTheme } from "../theme"
import { imgTitleProfileAvatar } from "../helpers/img-title-profile-avatar"
import { useOrganizationTeam } from "../services/hooks/useOrganization"
import { useTimer } from "../services/hooks/useTimer"
import { getTimerStatusValue } from "../helpers/get-timer-status"
import {
idleStatusIconLarge,
onlineAndTrackingTimeStatusIconLarge,
pauseStatusIconLarge,
suspendedStatusIconLarge
} from './svgs/icons';
import { SvgXml } from 'react-native-svg';
suspendedStatusIconLarge,
} from "./svgs/icons"
import { SvgXml } from "react-native-svg"

interface Props {
user: IUser;
size?: number;
user: IUser
size?: number
}
const ProfileImage: FC<Props> = ({ user, size }) => {
const { colors } = useAppTheme();
const { colors } = useAppTheme()

const { currentTeam } = useOrganizationTeam();
const { currentTeam } = useOrganizationTeam()

const currentMember = currentTeam?.members.find((currentMember) => currentMember.employee.userId === user.id);
const currentMember = currentTeam?.members?.find(
(currentMember) => currentMember.employee.userId === user.id,
)

const { timerStatus } = useTimer();
const { timerStatus } = useTimer()

const status = getTimerStatusValue(timerStatus, currentMember, currentTeam?.public);
const status = getTimerStatusValue(timerStatus, currentMember, currentTeam?.public)

const imageUrl = useMemo(
() => user?.image?.thumbUrl || user?.image?.fullUrl || user?.imageUrl,
[user?.image?.thumb, user]
);
[user?.image?.thumb, user],
)

let iconSvgXml = '';
let iconSvgXml = ""

switch (status) {
case 'online':
iconSvgXml = onlineAndTrackingTimeStatusIconLarge;
break;
case 'pause':
iconSvgXml = pauseStatusIconLarge;
break;
case 'idle':
iconSvgXml = idleStatusIconLarge;
break;
case 'suspended':
iconSvgXml = suspendedStatusIconLarge;
break;
case "online":
iconSvgXml = onlineAndTrackingTimeStatusIconLarge
break
case "pause":
iconSvgXml = pauseStatusIconLarge
break
case "idle":
iconSvgXml = idleStatusIconLarge
break
case "suspended":
iconSvgXml = suspendedStatusIconLarge
break
}

return (
Expand All @@ -66,16 +68,16 @@ const ProfileImage: FC<Props> = ({ user, size }) => {
width: size,
height: size,
borderColor:
status === 'online'
? '#6EE7B7'
: status === 'pause'
? '#EFCF9E'
: status === 'idle'
? '#F5BEBE'
: '#DCD6D6'
status === "online"
? "#6EE7B7"
: status === "pause"
? "#EFCF9E"
: status === "idle"
? "#F5BEBE"
: "#DCD6D6",
}}
source={{
uri: imageUrl
uri: imageUrl,
}}
/>
) : (
Expand All @@ -87,13 +89,13 @@ const ProfileImage: FC<Props> = ({ user, size }) => {
width: size,
height: size,
borderColor:
status === 'online'
? '#6EE7B7'
: status === 'pause'
? '#EFCF9E'
: status === 'idle'
? '#F5BEBE'
: '#DCD6D6'
status === "online"
? "#6EE7B7"
: status === "pause"
? "#EFCF9E"
: status === "idle"
? "#F5BEBE"
: "#DCD6D6",
}}
labelStyle={styles.prefix}
/>
Expand All @@ -105,41 +107,41 @@ const ProfileImage: FC<Props> = ({ user, size }) => {
borderRadius: 100,
width: 25,
height: 25,
position: 'absolute',
position: "absolute",
backgroundColor:
status === 'online'
? '#6EE7B7'
: status === 'pause'
? '#EFCF9E'
: status === 'idle'
? '#F5BEBE'
: '#DCD6D6',
alignItems: 'center',
justifyContent: 'center',
status === "online"
? "#6EE7B7"
: status === "pause"
? "#EFCF9E"
: status === "idle"
? "#F5BEBE"
: "#DCD6D6",
alignItems: "center",
justifyContent: "center",
borderColor: colors.background,
borderWidth: 3
borderWidth: 3,
}}
>
<SvgXml xml={iconSvgXml} />
</View>
</View>
</View>
);
};
export default ProfileImage;
)
}
export default ProfileImage

const styles = StyleSheet.create({
container: {
alignItems: 'center',
height: '10%'
alignItems: "center",
height: "10%",
},
prefix: {
fontFamily: typography.fonts.PlusJakartaSans.light,
fontSize: 42,
fontWeight: '200'
fontWeight: "200",
},
profileImage: {
borderRadius: 200,
borderWidth: 3
}
});
borderWidth: 3,
},
})
Loading

0 comments on commit 8f93c06

Please sign in to comment.