Skip to content

Commit

Permalink
Code optimize and Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
jekingohel committed Jan 5, 2024
1 parent 333d94f commit d75b03e
Show file tree
Hide file tree
Showing 47 changed files with 704 additions and 78 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ This mobile application allows users to search for GitHub profiles by username,
- Ensure the expected views are displayed after navigation.

## Time Investment
The completion of this project required a thoughtful investment of time. The total hours dedicated to the development, testing, and refinement of the GitHub Profile App amounted to 10 hours.
The completion of this project required a thoughtful investment of time. The total hours dedicated to the development, testing, and refinement of the GitHub Profile App amounted to 16 hours.

## Installation

Expand Down
12 changes: 2 additions & 10 deletions ios/GitHubProfileApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -581,11 +581,7 @@
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down Expand Up @@ -653,11 +649,7 @@
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down
6 changes: 3 additions & 3 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1351,7 +1351,7 @@ SPEC CHECKSUMS:
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
FlipperKit: 37525a5d056ef9b93d1578e04bc3ea1de940094f
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
glog: 035f1e36e53b355cf70f6434d161b36e7d21fecd
hermes-engine: 34df9d5034e90bd9bf1505e1ca198760373935af
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
Expand Down Expand Up @@ -1402,8 +1402,8 @@ SPEC CHECKSUMS:
RNReanimated: 57f436e7aa3d277fbfed05e003230b43428157c0
RNScreens: b582cb834dc4133307562e930e8fa914b8c04ef2
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Yoga: 522ef80503e6134a1829f3dcbacc698a0f69bdac
Yoga: 4f53dc50008d626fa679c7a1cb4bed898f8c0bde

PODFILE CHECKSUM: 4709e221307851de37be8fcfec02e0e719fa8d94

COCOAPODS: 1.12.1
COCOAPODS: 1.14.3
17 changes: 17 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
{
"name": "GitHubProfileApp",
"version": "0.0.1",
"author": "Jekin Gohel <jekin1991@gmail.com>",
"private": true,
"description": "This mobile application allows users to search for GitHub profiles by username, view user details, and navigate through followers and following lists. The app fetches GitHub user data using the GitHub REST API.",
"repository": {
"type": "git",
"url": "https://github.com/jekingohel/GitHubProfileApp.git"
},
"homepage": "https://github.com/jekingohel/GitHubProfileApp",
"keywords": [
"react",
"react-native",
"GitHub",
"GitHub Users",
"followers",
"following",
"GitHub REST API",
"search"
],
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
Expand Down
1 change: 0 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import AppNavigator from './navigation/AppNavigator';
import 'react-native-gesture-handler';
import {Provider} from 'react-redux';
import Store from './store';
import 'react-native-devsettings';

function App(): React.JSX.Element {
return (
Expand Down
16 changes: 16 additions & 0 deletions src/__shared/components/ActionButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ type propsType = PropsWithChildren<{
style?: object;
}>;

/**
* Functional component for an action button with a title and optional subtitle.
* @param {object} props - Component properties.
* @param {string} props.subTitle - Optional subtitle text.
* @param {() => void} props.onPress - Callback function for the button press event.
* @param {string} props.title - Title text for the button.
* @param {object} props.style - Additional styles for the button.
* @returns {JSX.Element} - Action button component.
* @example
* <ActionBtn
* subTitle="followers"
* onPress={() => handlePress()}
* title="123"
* style={{ marginTop: 10 }}
* />
*/
function ActionBtn({
subTitle,
onPress,
Expand Down
25 changes: 25 additions & 0 deletions src/__shared/components/AppContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,48 @@ interface AppContainerProps {
children: ReactNode;
}

/**
* Functional component for a container that handles keyboard avoiding and status bar configuration.
* @param {object} props - Component properties.
* @param {boolean} [props.scrollBar=true] - Controls the visibility of the vertical scroll bar in the ScrollView.
* @param {boolean} [props.scroll=true] - Enables or disables scrolling behavior.
* @param {string | null} [props.statusBarColor='#FFFFFF'] - Color of the status bar.
* @param {boolean} [props.loader=false] - Flag indicating whether a loader is displayed.
* @param {number} [props.loaderSize] - Size of the loader.
* @param {ReactNode} props.children - The content to be rendered inside the container.
* @returns {JSX.Element} - AppContainer component.
* @example
* <AppContainer
* scrollBar={true}
* scroll={true}
* statusBarColor="#FFFFFF"
* loader={false}
* loaderSize={30}
* >
* // Content goes here
* </AppContainer>
*/
const AppContainer: React.FC<AppContainerProps> = props => {
const {scrollBar, scroll = true} = props;
const keyboardVerticalOffset = Platform.OS === 'ios' ? 40 : 0;

return (
<SafeAreaView style={{flex: 1}}>
{/* KeyboardAvoidingView provides automatic keyboard behavior */}
<KeyboardAvoidingView
style={{flex: 1, backgroundColor: '#FFFFFF'}}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={keyboardVerticalOffset}
{...props}>
{/* StatusBar for controlling status bar appearance */}
<StatusBar
animated={false}
backgroundColor={'#FFFFFF'}
hidden={false}
/>

{scroll ? (
// ScrollView provides a scrollable container for content
<ScrollView
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={scrollBar ?? false}
Expand All @@ -42,6 +66,7 @@ const AppContainer: React.FC<AppContainerProps> = props => {
{props.children}
</ScrollView>
) : (
// Render content directly if scrolling is disabled
props.children
)}
</KeyboardAvoidingView>
Expand Down
29 changes: 29 additions & 0 deletions src/__shared/components/Avatar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import {Image, Pressable} from 'react-native';
import Text from '../Text';

// Define the type of properties that Avatar component accepts
interface AvatarProps {
source: string | null;
title: string;
Expand All @@ -19,12 +20,39 @@ interface AvatarProps {
imageProps?: object;
}

// Size mapping for different avatar sizes
const sizeArray = {
small: 28,
medium: 38,
large: 70,
};

/**
* JSX Component for rendering an Avatar, either as an image or with a background color and text.
* @param {object} props - Properties for configuring the Avatar.
* @param {string | null} props.source - Source URI for the image. Set to null for text-only avatars.
* @param {string} props.title - Title or text content for the avatar.
* @param {boolean} [props.rounded=false] - Determines if the avatar should have rounded corners.
* @param {'large' | 'medium' | 'small'} props.size - Size of the avatar, can be 'large', 'medium', or 'small'.
* @param {() => void} [props.onPress] - Callback function for press events.
* @param {string} [props.backgroundColor='rgba(142,142,147,.8)'] - Background color for text-only avatars.
* @param {string} [props.textColor='#FFFFFF'] - Text color for text-only avatars.
* @param {string | null} [props.customColor] - Custom background color for the avatar.
* @param {number} [props.customSize] - Custom size for the avatar.
* @param {boolean} [props.loading] - Determines if the avatar is in a loading state.
* @param {object} [props.containerStyle] - Additional styles for the avatar container.
* @param {boolean} [props.singleLetter] - Displays only the first letter of the title.
* @param {boolean} [props.fullView] - Enables full view mode, allowing press events even without an onPress callback.
* @param {object} [props.imageProps] - Additional properties for the Image component when source is provided.
* @returns {JSX.Element} - Avatar component.
* @example
* <Avatar
* source="https://example.com/avatar.jpg"
* title="John Doe"
* size="medium"
* onPress={() => console.log('Avatar pressed!')}
* />
*/
const Avatar: React.FC<AvatarProps> = props => {
const {
containerStyle,
Expand All @@ -45,6 +73,7 @@ const Avatar: React.FC<AvatarProps> = props => {
?.join('')
?.toUpperCase();

// Return either a text-only or image-based avatar based on the presence of a source URI
return source === null ? (
<Pressable
onPress={onPress}
Expand Down
12 changes: 12 additions & 0 deletions src/__shared/components/Container/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@ import React from 'react';
import {ViewStyle} from 'react-native';
import View from '../View';

// Define the type of properties that Container component accepts
interface CustomViewProps {
children: React.ReactNode;
style?: ViewStyle;
}

/**
* JSX Component for a custom container view with predefined styling.
* @param {object} props - Properties for configuring the Container.
* @param {React.ReactNode} props.children - Child components to be rendered within the container.
* @param {ViewStyle} [props.style] - Additional styles to be applied to the container.
* @returns {JSX.Element} - Container component.
* @example
* <Container style={{margin: 10}}>
* <Text>This is a custom container.</Text>
* </Container>
*/
const Container: React.FC<CustomViewProps> = props => {
return (
<View
Expand Down
43 changes: 43 additions & 0 deletions src/__shared/components/ScrollableContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ScrollViewProps,
} from 'react-native';

// Define the type of properties that ScrollableContainer component accepts
interface ScrollableContainerProps extends ScrollViewProps {
backgroundColor?: string;
horizontal?: boolean;
Expand All @@ -24,6 +25,42 @@ interface ScrollableContainerProps extends ScrollViewProps {
scrollToTopPostion?: number;
}

/**
* JSX Component for a scrollable container with customizable features.
* @param {object} props - Properties for configuring the ScrollableContainer.
* @param {string} [props.backgroundColor] - Background color of the scrollable container.
* @param {boolean} [props.horizontal] - Determines if the scroll should be horizontal.
* @param {boolean} [props.scrollBar] - Determines if the scroll bar should be visible.
* @param {object} [props.wrapperStyle] - Additional styles to be applied to the container.
* @param {boolean} [props.refresh] - Enables pull-to-refresh functionality.
* @param {boolean} [props.refreshing] - Indicates whether the pull-to-refresh is in progress.
* @param {boolean} [props.scrollLoader] - Indicates whether to show a loader during scrolling.
* @param {() => void} [props.onRefresh] - Callback function when pull-to-refresh is triggered.
* @param {(event: object, isEndReached: boolean) => void} [props.handelScroll] - Callback for handling scroll events.
* @param {ScrollViewProps['onScroll']} [props.onScroll] - Callback for handling scroll events.
* @param {React.RefObject<ScrollView>} [props.scrollref] - Reference to the ScrollView component.
* @param {boolean} [props.scrollToTop] - Indicates whether to scroll to the top.
* @param {number} [props.scrollToTopPostion] - Position to scroll to when scrollToTop is true.
* @returns {JSX.Element} - ScrollableContainer component.
* @example
* <ScrollableContainer
* backgroundColor="#F5F5F5"
* horizontal={false}
* scrollBar={true}
* refresh={true}
* refreshing={false}
* onRefresh={() => console.log('Refreshing...')}
* handelScroll={(event, isEndReached) => {
* console.log('Scrolling...', isEndReached);
* }}
* onScroll={(event) => console.log('Scrolling...', event)}
* scrollref={scrollRef}
* scrollToTop={true}
* scrollToTopPostion={0}
* >
* /* Add your scrollable content here
* </ScrollableContainer>
*/
const ScrollableContainer: React.FC<ScrollableContainerProps> = props => {
const {
backgroundColor,
Expand All @@ -42,9 +79,13 @@ const ScrollableContainer: React.FC<ScrollableContainerProps> = props => {
...restProps
} = props;

// Create a ref for the ScrollView component
const scrollRef = scrollref || useRef<ScrollView>(null);

// State to track whether to show the scroll to top button
const [scrollToTopBtn, setScrollToTopBtn] = useState(false);

// Callback function to handle scroll events
const handelOnScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
const {layoutMeasurement, contentOffset, contentSize} = event.nativeEvent;

Expand All @@ -59,6 +100,7 @@ const ScrollableContainer: React.FC<ScrollableContainerProps> = props => {
}
};

// Effect to scroll to the top when scrollToTop and scrollToTopPostion are provided
useEffect(() => {
if (scrollToTop && scrollToTopPostion && scrollRef.current) {
scrollRef.current.scrollTo({
Expand All @@ -68,6 +110,7 @@ const ScrollableContainer: React.FC<ScrollableContainerProps> = props => {
}
}, [scrollToTop, scrollToTopPostion]);

// Render the ScrollableContainer component
return (
<Animated.ScrollView
testID="scroll-view"
Expand Down
Loading

0 comments on commit d75b03e

Please sign in to comment.