Skip to content

Commit

Permalink
feat(apps/mobile): track when an image is being uploaded
Browse files Browse the repository at this point in the history
  • Loading branch information
hassankhan committed Oct 14, 2024
1 parent dae7cff commit a01da16
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 0 deletions.
3 changes: 3 additions & 0 deletions apps/mobile/src/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { UploadButton } from '../components/UploadButton';
import { ImageList } from '../features/HomePage/ImageList';
import { NoImagesFound } from '../features/HomePage/NoImagesFound';
import { UploadImageSheet } from '../features/UploadImageModal/UploadImageSheet';
import { useAppSelector } from '../store/overrides';
import { getIsImageUploading } from '../store/selectors/getIsImageUploading';
import {
useGetMyFavouritesQuery,
useGetMyImagesQuery,
Expand All @@ -24,6 +26,7 @@ const Home = () => {
const isLoading = isImagesLoading || isFavouritesLoading || isVotesLoading;

const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false);
const isImageUploading = useAppSelector(getIsImageUploading);

const handleUploadButtonPress = useCallback(() => {
setIsBottomSheetOpen(true);
Expand Down
94 changes: 94 additions & 0 deletions apps/mobile/src/features/CatCard/CatCardSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useEffect } from 'react';
import { View } from 'react-native';
import { createStyleSheet, useStyles } from 'react-native-unistyles';
import FontAwesome from '@expo/vector-icons/FontAwesome';
import Animated, {
useAnimatedStyle,
useDerivedValue,
useSharedValue,
withRepeat,
withSequence,
withTiming,
} from 'react-native-reanimated';

export const CatCardSkeleton = () => {
const { styles } = useStyles(stylesheet);

const val1 = useSharedValue(0.6);

useEffect(() => {
'worklet';
val1.value = withRepeat(
withSequence(
withTiming(1, { duration: 1000 }),
withTiming(0.6, { duration: 1000 })
),
0
);
}, []);

const val2 = useDerivedValue(() => {
return 0.6 + 1 - val1.value;
});

const dotStyle = useAnimatedStyle(() => ({
opacity: val1.value,
}));

const dotStyle2 = useAnimatedStyle(() => ({
opacity: val2.value,
}));

return (
<View style={styles.root}>
<Animated.View style={[styles.image, dotStyle]}>
<FontAwesome
name={'circle'}
color={'#e3e0e0'}
size={65}
style={{ marginVertical: 2, marginHorizontal: 8 }}
/>
<FontAwesome
name={'circle'}
color={'#e3e0e0'}
size={65}
style={{ marginVertical: 2, marginHorizontal: 8 }}
/>
</Animated.View>
<Animated.View style={[styles.base, dotStyle2]}>
<FontAwesome name={'circle'} color={'#c9c8c8'} size={40} />
<FontAwesome name={'circle'} color={'#c9c8c8'} size={40} />
<FontAwesome name={'circle'} color={'#c9c8c8'} size={40} />
</Animated.View>
</View>
);
};

const stylesheet = createStyleSheet((theme) => ({
root: {
borderColor: theme.colors.background.$6,
borderRadius: theme.radii.$3,
borderWidth: theme.borderWidths.$1,
width: theme.space.full,
marginVertical: 15,
},
base: {
borderBottomLeftRadius: theme.radii.$3,
borderBottomRightRadius: theme.radii.$3,
width: theme.space.full,
height: 80,
backgroundColor: '#fff',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-evenly',
},
image: {
borderTopLeftRadius: theme.radii.$3,
borderTopRightRadius: theme.radii.$3,
width: theme.space.full,
height: 180,
backgroundColor: '#c9c8c8',
justifyContent: 'flex-start',
alignItems: 'flex-end',
},
}));
4 changes: 4 additions & 0 deletions apps/mobile/src/store/selectors/getIsImageUploading.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { RootState } from '../store';

export const getIsImageUploading = (state: RootState) =>
state.imageActivity.isImageUploading;
33 changes: 33 additions & 0 deletions apps/mobile/src/store/slices/ImageActivitySlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createSlice } from '@reduxjs/toolkit';
import { CatApi } from '../services/CatApi';

const initialState = {
isImageUploading: false,
};

export const ImageActivitySlice = createSlice({
name: 'imageActivity',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addMatcher(
CatApi.endpoints.uploadImage.matchPending,
(state, { payload }) => {
state.isImageUploading = true;
}
)
.addMatcher(
CatApi.endpoints.uploadImage.matchFulfilled,
(state, { payload }) => {
state.isImageUploading = false;
}
)
.addMatcher(
CatApi.endpoints.uploadImage.matchRejected,
(state, { payload }) => {
state.isImageUploading = false;
}
);
},
});
3 changes: 3 additions & 0 deletions apps/mobile/src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import devToolsEnhancer from 'redux-devtools-expo-dev-plugin';
import { ToastMiddleware } from './middleware/ToastMiddleware';

import { CatApi } from './services/CatApi';
import { ImageActivitySlice } from './slices/ImageActivitySlice';

export const store = configureStore({
enhancers: (getDefaultEnhancers) =>
Expand All @@ -19,6 +20,8 @@ export const store = configureStore({
reducer: {
// RTK-Query reducers
[CatApi.reducerPath]: CatApi.reducer,
// RTK slices
[ImageActivitySlice.name]: ImageActivitySlice.reducer,
},
});

Expand Down

0 comments on commit a01da16

Please sign in to comment.