Skip to content
This repository has been archived by the owner on Sep 21, 2021. It is now read-only.

Commit

Permalink
feat: save progress
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronna Firmo committed Apr 27, 2021
1 parent f32f85f commit 6426085
Show file tree
Hide file tree
Showing 16 changed files with 384 additions and 5 deletions.
22 changes: 19 additions & 3 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';

import { kkAPIClient } from './api/KkAPIClient';
import useCachedResources from './hooks/useCachedResources';
import useColorScheme from './hooks/useColorScheme';
import Navigation from './navigation';
import { Environment } from './KkEnvironment';
import { createKkNavigation } from './navigation/KkNavigation';
import { localStorageService } from './services/KkLocalStorageService';

export default function App() {
const isLoadingComplete = useCachedResources();
const colorScheme = useColorScheme();

const { Navigator, navigate } = createKkNavigation();

Environment.set({
api: kkAPIClient({
baseUrl: 'https://api.clockify.me/api/v1',
}),
navigation: {
navigate,
},
services: {
localStorage: localStorageService,
},
});

if (!isLoadingComplete) {
return null;
} else {
return (
<SafeAreaProvider>
<Navigation colorScheme={colorScheme} />
<Navigator colorScheme={colorScheme} />
<StatusBar />
</SafeAreaProvider>
);
Expand Down
41 changes: 41 additions & 0 deletions KkEnvironment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { API } from './api/KkAPIClient';
import { LocalStorageService } from './services/KkLocalStorageService';

type KkEnvironment = {
/** The current API */
api: API;
/** A proxy for handling navigation */
navigation: {
/** Navigates to the provided `route`, using the given `params` */
navigate: (route: string, params?: { [key: string]: any }) => void;
};
/** Currently available services */
services: {
/** A service for interacting with async storage */
localStorage: LocalStorageService;
};
};

/** This value holds the actual environment object. */
let _currentEnvironment: KkEnvironment | undefined = undefined;

/** Exposes the current `StraveEnvironment` via `current()`. */
const Environment = {
/** Returns the current environment. */
current(): KkEnvironment {
return { ..._currentEnvironment! };
},

/**
* Sets the current environment. Call as early as possible during startup, and
* ONLY call once.
*/
set(environment: KkEnvironment) {
if (_currentEnvironment === undefined) {
_currentEnvironment = environment;
}
},
};

Object.freeze(Environment);
export { Environment };
16 changes: 16 additions & 0 deletions api/KkAPIClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Workplace } from './models/Workplace';

export type API = {
getWorkspaces: () => Promise<Workplace>;
};

export const kkAPIClient = (options: { baseUrl: string }): API => {
const getUrl = (url: string) => `${options.baseUrl}/${url}`;
return {
getWorkspaces: async () => {
const response = await fetch(getUrl('/workspaces'));
const result = await response.json();
return result;
},
};
};
4 changes: 4 additions & 0 deletions api/models/Workplace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type Workplace = {
id: string;
name: string;
};
11 changes: 11 additions & 0 deletions components/KkSizedBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { View } from './Themed';

type Props = {
height?: number;
width?: number;
};

export const KkSizedBox = (props: Props) => {
return <View style={{ height: props.height, width: props.width }} />;
};
90 changes: 90 additions & 0 deletions components/KkStyles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { StyleSheet, TextStyle, ViewStyle } from 'react-native';

type FontOptions = {
bold?: boolean;
size?: number;
};

type Fonts = {
h1: (options?: FontOptions) => TextStyle;
h2: (options?: FontOptions) => TextStyle;
h3: (options?: FontOptions) => TextStyle;
h4: (options?: FontOptions) => TextStyle;
h5: (options?: FontOptions) => TextStyle;
h6: (options?: FontOptions) => TextStyle;
subtitle1: (options?: FontOptions) => TextStyle;
subtitle2: (options?: FontOptions) => TextStyle;
body1: (options?: FontOptions) => TextStyle;
body2: (options?: FontOptions) => TextStyle;
button: (options?: FontOptions) => TextStyle;
caption: (options?: FontOptions) => TextStyle;
overline: (options?: FontOptions) => TextStyle;
};

// If you want to see it visually:
// https://material.io/design/typography/the-type-system.html#type-scale
export const fonts: Fonts = {
h1: (options) => ({
fontWeight: options?.bold ? 'bold' : '300',
fontSize: 96,
letterSpacing: -1.5,
}),
h2: (options) => ({
fontSize: 60,
fontWeight: options?.bold ? 'bold' : '300',
letterSpacing: -0.5,
}),
h3: (options) => ({
fontSize: 48,
fontWeight: options?.bold ? 'bold' : '400',
}),
h4: (options) => ({
fontSize: 34,
fontWeight: options?.bold ? 'bold' : '400',
letterSpacing: 0.25,
}),
h5: (options) => ({
fontSize: 24,
fontWeight: options?.bold ? 'bold' : '400',
}),
h6: (options) => ({
fontSize: 20,
fontWeight: options?.bold ? 'bold' : '500',
letterSpacing: 0.15,
}),
subtitle1: (options) => ({
fontSize: 16,
fontWeight: options?.bold ? 'bold' : '400',
letterSpacing: 0.15,
}),
subtitle2: (options) => ({
fontSize: 14,
fontWeight: options?.bold ? 'bold' : '500',
letterSpacing: 0.1,
}),
body1: (options) => ({
fontSize: 16,
fontWeight: options?.bold ? 'bold' : '400',
letterSpacing: 0.5,
}),
body2: (options) => ({
fontSize: 14,
fontWeight: options?.bold ? 'bold' : '400',
letterSpacing: 0.25,
}),
button: (options) => ({
fontSize: 14,
fontWeight: options?.bold ? 'bold' : '400',
letterSpacing: 1.25,
}),
caption: (options) => ({
fontSize: 12,
fontWeight: options?.bold ? 'bold' : '400',
letterSpacing: 0.4,
}),
overline: (options) => ({
fontSize: 10,
fontWeight: options?.bold ? 'bold' : '400',
letterSpacing: 1.5,
}),
};
36 changes: 36 additions & 0 deletions containers/KkLandingContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useState } from 'react';
import { kkAPIClient } from '../api/KkAPIClient';
import { Environment } from '../KkEnvironment';
import { routes } from '../navigation/KkNavigation';
import { KkLandingScreen } from '../screens/KkLandingScreen';
import { localStorageKey } from '../services/KkLocalStorageService';

export type KkLandingProps = {
formState: FormState;
userUpdatedForm: React.Dispatch<React.SetStateAction<FormState>>;
userSubmittedForm: () => void;
};

type FormState = {
apiKey: string;
};

export const KkLandingContainer = (props: KkLandingProps) => {
const [formState, setFormState] = useState<FormState>({ apiKey: '' });

const { services, navigation } = Environment.current();

return (
<KkLandingScreen
formState={formState}
userUpdatedForm={setFormState}
userSubmittedForm={async () => {
await services.localStorage.storeItem(
localStorageKey.API_KEY,
formState.apiKey
);
navigation.navigate(routes.WORKSPACE);
}}
/>
);
};
8 changes: 8 additions & 0 deletions containers/KkWorkspaceContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
import { KkWorspaceScreen } from '../screens/KkWorspaceScreen';

export type KkWorkspaceProps = {};

export const KkWorkspaceContainer = (props: KkWorkspaceProps) => {
return <KkWorspaceScreen />;
};
5 changes: 4 additions & 1 deletion hooks/useColorScheme.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { ColorSchemeName, useColorScheme as _useColorScheme } from 'react-native';
import {
ColorSchemeName,
useColorScheme as _useColorScheme,
} from 'react-native';

// The useColorScheme value is always either light or dark, but the built-in
// type suggests that it can be null. This will not happen in practice, so this
Expand Down
50 changes: 50 additions & 0 deletions navigation/KkNavigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
DarkTheme,
DefaultTheme,
NavigationContainer,
NavigationContainerRef,
} from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import { ColorSchemeName } from 'react-native';
import { KkLandingContainer } from '../containers/KkLandingContainer';
import { KkWorkspaceContainer } from '../containers/KkWorkspaceContainer';

export const routes = {
LANDING: 'Landing',
WORKSPACE: 'Workspace',
};

export const createKkNavigation = (): {
Navigator: React.ComponentType<{ colorScheme: ColorSchemeName }>;
navigate: (route: string, params?: { [key: string]: any }) => void;
} => {
let navigatorRef: NavigationContainerRef | null = null;
return {
navigate: (route, params) => {
navigatorRef?.navigate(route, params);
},
Navigator: (props) => (
<NavigationContainer
ref={(ref) => (navigatorRef = ref)}
theme={props.colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<KkRootNavigator />
</NavigationContainer>
),
};
};

// A root stack navigator is often used for displaying modals on top of all other content
// Read more here: https://reactnavigation.org/docs/modal
const RootStack = createStackNavigator();
const KkRootNavigator = () => {
return (
<RootStack.Navigator screenOptions={{ headerShown: false }}>
<RootStack.Screen name={routes.LANDING} component={KkLandingContainer} />
<RootStack.Screen
name={routes.WORKSPACE}
component={KkWorkspaceContainer}
/>
</RootStack.Navigator>
);
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"dependencies": {
"@expo/vector-icons": "^12.0.0",
"@react-native-async-storage/async-storage": "^1.13.0",
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/bottom-tabs": "5.11.2",
"@react-navigation/native": "~5.8.10",
Expand All @@ -28,8 +29,8 @@
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
"react-native-reanimated": "~2.1.0",
"react-native-gesture-handler": "~1.10.2",
"react-native-reanimated": "~2.1.0",
"react-native-safe-area-context": "3.2.0",
"react-native-screens": "~3.0.0",
"react-native-web": "~0.13.12"
Expand Down
3 changes: 3 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# klakie docu

> Anything that doesn't begin with `Kk` is part of the generated expo template
45 changes: 45 additions & 0 deletions screens/KkLandingScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { Button, StyleSheet, TextInput } from 'react-native';
import { KkSizedBox } from '../components/KkSizedBox';
import { fonts } from '../components/KkStyles';
import { Text, View } from '../components/Themed';
import { KkLandingProps } from '../containers/KkLandingContainer';

export const KkLandingScreen = (props: KkLandingProps) => {
return (
<View style={styles.container}>
<View style={styles.container}>
<Text style={fonts.h6({ bold: true })}>Welcome to Klakie!</Text>
</View>
<View style={styles.container}>
<Text style={fonts.body1()}>Enter your API Key</Text>
<KkSizedBox height={24} />
<TextInput
style={styles.input}
value={props.formState.apiKey}
onSubmitEditing={props.userSubmittedForm}
onChangeText={(text) =>
props.userUpdatedForm((prevState) => ({
...prevState,
apiKey: text,
}))
}
/>
</View>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
input: {
...fonts.body1(),
color: 'white',
border: '1px solid white',
padding: 8,
},
});
11 changes: 11 additions & 0 deletions screens/KkWorspaceScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { Text, View } from '../components/Themed';
import { KkWorkspaceProps } from '../containers/KkWorkspaceContainer';

export const KkWorspaceScreen = (props: KkWorkspaceProps) => {
return (
<View>
<Text>Hello world</Text>
</View>
);
};
Loading

0 comments on commit 6426085

Please sign in to comment.