diff --git a/README.md b/README.md index 6d16ec1..5d6d291 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,4 @@ This is a micro-framework for React Native which is designed to help simplify de # Screenshots -​ splash        dashboard       login +​ splash        dashboard       login        dashboard       login diff --git a/packages/data/src/out/database_port.ts b/packages/data/src/out/database_port.ts index fa2d937..0d2f199 100644 --- a/packages/data/src/out/database_port.ts +++ b/packages/data/src/out/database_port.ts @@ -4,4 +4,5 @@ export interface DatabasePort { addUser(params?: { email: string; password: string; token: string }): Promise fetchUserData(data: UserModel): Promise fetchUserExists(data: UserModel): Promise + removeUser(params: { email: string }): Promise } diff --git a/packages/data/src/repositories/user_repository_impl.ts b/packages/data/src/repositories/user_repository_impl.ts index 421980a..2f7ea5d 100644 --- a/packages/data/src/repositories/user_repository_impl.ts +++ b/packages/data/src/repositories/user_repository_impl.ts @@ -14,7 +14,6 @@ export class UserRepositoryImpl implements UserRepository { async login(params?: { email: string; password: string }): Promise { const usermodel: any = await this.network.login({ email: params.email, password: params.password }) - console.log(usermodel) if (usermodel == 'Request failed with status code 403') { return usermodel } else { @@ -31,9 +30,16 @@ export class UserRepositoryImpl implements UserRepository { email: params.email }) } + async fetchUserExists(params?: { email: string }): Promise { return await this.database.fetchUserExists({ email: params.email }) } + + async logout(params?: { email: string }): Promise { + return await this.database.removeUser({ + email: params.email + }) + } } diff --git a/packages/database-watermelon/src/dao/user_dao.ts b/packages/database-watermelon/src/dao/user_dao.ts index bb46b8a..84db18a 100644 --- a/packages/database-watermelon/src/dao/user_dao.ts +++ b/packages/database-watermelon/src/dao/user_dao.ts @@ -39,4 +39,14 @@ export class UserDao extends BaseDao { if (userCount > 0) return true else return false } + + async deleteUser(data: { email: string }): Promise { + await safeDbCall( + this.attachedDatabase.write(async () => { + const response: any = await this.databaseData.query(Q.where('email', Q.eq(data.email))).destroyAllPermanently() + return response + }) + ) + return true + } } diff --git a/packages/database-watermelon/src/database_adapter.ts b/packages/database-watermelon/src/database_adapter.ts index 96b5679..b8b9ae3 100644 --- a/packages/database-watermelon/src/database_adapter.ts +++ b/packages/database-watermelon/src/database_adapter.ts @@ -28,5 +28,10 @@ class DatabaseAdapter implements DatabasePort { email: data.email }) } + async removeUser(params: { email: string }): Promise { + return await this.databases.userDao.deleteUser({ + email: params.email + }) + } } export default DatabaseAdapter diff --git a/packages/domain/src/di/domain_module.ts b/packages/domain/src/di/domain_module.ts index 7433dae..023ea43 100644 --- a/packages/domain/src/di/domain_module.ts +++ b/packages/domain/src/di/domain_module.ts @@ -2,13 +2,15 @@ import { UserRepository } from './../repository/user_repository' import { DataModule } from 'data' import { Graph, ObjectGraph, Provides, Singleton } from 'di' import { LoginUseCase } from '../usecases/login_user_usecase' -import { FetchUserDataUseCase, FetchUserExistsUseCase } from '../domain' +import { LogoutUseCase } from '../usecases/logout_usecase' +import { FetchUserDataUseCase } from '../usecases/user_details_usecase' +import { FetchUserExistsUseCase } from '../usecases/user_present_data_usecase' @Singleton() @Graph({ subgraphs: [DataModule] }) export class DomainModule extends ObjectGraph { @Provides() - providesLoginUseCase(provideUserRepository: UserRepository): LoginUseCase { + provideLoginUseCase(provideUserRepository: UserRepository): LoginUseCase { return new LoginUseCase(provideUserRepository) } @Provides() @@ -19,4 +21,8 @@ export class DomainModule extends ObjectGraph { provideUserExistsUseCase(provideUserRepository: UserRepository): FetchUserExistsUseCase { return new FetchUserExistsUseCase(provideUserRepository) } + @Provides() + provideLogoutUseCase(provideUserRepository: UserRepository): LogoutUseCase { + return new LogoutUseCase(provideUserRepository) + } } diff --git a/packages/domain/src/domain.ts b/packages/domain/src/domain.ts index 45c16bd..421e4cd 100644 --- a/packages/domain/src/domain.ts +++ b/packages/domain/src/domain.ts @@ -3,6 +3,7 @@ import { FetchUserDataUseCase, FetchUserDataUseCaseParams } from './usecases/use import { LoginUseCase, LoginParams } from './usecases/login_user_usecase' import { DomainModule } from './di/domain_module' import { UserRepository } from './repository/user_repository' +import { LogoutUseCase, LogoutParams } from './usecases/logout_usecase' export { DomainModule, @@ -12,5 +13,7 @@ export { FetchUserDataUseCase, FetchUserDataUseCaseParams, FetchUserExistsUseCase, - FetchUserExistsUseCaseParams + FetchUserExistsUseCaseParams, + LogoutUseCase, + LogoutParams } diff --git a/packages/domain/src/repository/user_repository.ts b/packages/domain/src/repository/user_repository.ts index 96a6f6d..0699f8d 100644 --- a/packages/domain/src/repository/user_repository.ts +++ b/packages/domain/src/repository/user_repository.ts @@ -4,4 +4,5 @@ export interface UserRepository { login(params?: { email: string; password: string }): Promise fetchUserData(params?: { email: string }): Promise fetchUserExists(params?: { email: string }): Promise + logout(params?: { email: string }): Promise } diff --git a/packages/domain/src/usecases/logout_usecase.ts b/packages/domain/src/usecases/logout_usecase.ts new file mode 100644 index 0000000..aa40d8f --- /dev/null +++ b/packages/domain/src/usecases/logout_usecase.ts @@ -0,0 +1,29 @@ +import { UserRepository } from '../repository/user_repository' +import { FutureUseCase } from './base/base_usecase' +import { Params } from './base/params' + +export class LogoutUseCase extends FutureUseCase { + private readonly userRepository: UserRepository + constructor(repo: UserRepository) { + super() + this.userRepository = repo + } + async execute(params?: LogoutParams): Promise { + if (params?.verify()) { + return await this.userRepository.logout({ + email: params.email + }) + } else return false + } +} +export class LogoutParams extends Params { + readonly email?: string + + constructor(params?: { email: string }) { + super({}) + this.email = params.email + } + verify(): boolean { + return true + } +} diff --git a/packages/localisation/lib/en.json b/packages/localisation/lib/en.json index 4bdc3cb..e1b5a03 100644 --- a/packages/localisation/lib/en.json +++ b/packages/localisation/lib/en.json @@ -11,5 +11,6 @@ "getThere": "Get There.", "getStarted": "Get Started", "noInput": "please enter data or a valid data", - "errorMessage": "please enter proper email and password" + "errorMessage": "please enter proper email and password", + "logout": "Logout" } diff --git a/packages/mobile/App.tsx b/packages/mobile/App.tsx index f47801b..9885bd1 100644 --- a/packages/mobile/App.tsx +++ b/packages/mobile/App.tsx @@ -16,10 +16,6 @@ import SplashScreen from 'react-native-splash-screen' import { ThemeProvider } from './src/theme/themeprovider' class App extends Component { - componentDidMount(): void { - SplashScreen.hide() - } - render() { return ( diff --git a/packages/mobile/src/assets/images.ts b/packages/mobile/src/assets/images.ts index ff2f01a..b8baa03 100644 --- a/packages/mobile/src/assets/images.ts +++ b/packages/mobile/src/assets/images.ts @@ -2,6 +2,8 @@ const Images = { icon: require('./images/logo.png'), car: require('./images/car.png'), carBlack: require('./images/carblack.png'), - iconBlack: require('./images/logoblack.png') + iconBlack: require('./images/logoblack.png'), + blackLogout: require('./images/blacklogouticon.png'), + whiteLogout: require('./images/whitelogouticon.png') } export default Images diff --git a/packages/mobile/src/assets/images/blacklogouticon.png b/packages/mobile/src/assets/images/blacklogouticon.png new file mode 100644 index 0000000..973a026 Binary files /dev/null and b/packages/mobile/src/assets/images/blacklogouticon.png differ diff --git a/packages/mobile/src/assets/images/whitelogouticon.png b/packages/mobile/src/assets/images/whitelogouticon.png new file mode 100644 index 0000000..fb224a5 Binary files /dev/null and b/packages/mobile/src/assets/images/whitelogouticon.png differ diff --git a/packages/mobile/src/feature/dashboard/dashboard_screen.tsx b/packages/mobile/src/feature/dashboard/dashboard_screen.tsx index 1143fb9..e35840c 100644 --- a/packages/mobile/src/feature/dashboard/dashboard_screen.tsx +++ b/packages/mobile/src/feature/dashboard/dashboard_screen.tsx @@ -6,22 +6,35 @@ import { AppButton } from '../../widgets/app_button/app_button' import { useTheme } from '../../theme/themeprovider' import { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' +import { logoutAction } from 'presentation' +import { useNavigation } from '@react-navigation/native' +import RoutePaths from '../../navigation/router_path' import { fetchUserAction } from 'presentation' const DashboardScreen = () => { const { theme, isDark } = useTheme() - const [lodingState, setLodingState] = useState(false) + const navigation: any = useNavigation() const databaseEmail: any = useSelector((state: any) => state?.userData?.data?.payload) + const logoutData: any = useSelector((state: any) => state?.logout?.data?.payload) const dispatch = useDispatch() useEffect(() => { dispatch(fetchUserAction({})) }, []) + const onLogoutClick = () => { + dispatch(logoutAction({ databaseEmail })) + } return ( + onLogoutClick()}> + + {`${i18n.t('uber')} - ${databaseEmail}`} {i18n.t('getThere')} - diff --git a/packages/mobile/src/feature/dashboard/dashboard_style.ts b/packages/mobile/src/feature/dashboard/dashboard_style.ts index 6e36c88..33c1234 100644 --- a/packages/mobile/src/feature/dashboard/dashboard_style.ts +++ b/packages/mobile/src/feature/dashboard/dashboard_style.ts @@ -12,9 +12,9 @@ export default StyleSheet.create({ height: '75%' }, uberText: { - fontSize: 40, + fontSize: 28, textAlign: 'center', - marginTop: '15%', + marginTop: '10%', fontFamily: 'Poppins-Regular' }, getText: { @@ -33,7 +33,18 @@ export default StyleSheet.create({ height: 350, alignSelf: 'center', position: 'absolute', - bottom: 20, + bottom: 30, right: -100 + }, + logoutStyle: { + marginTop: 10, + width: 30, + height: 30, + alignSelf: 'flex-end' + }, + logoutButton: { + width: 30, + height: 30, + alignSelf: 'flex-end' } }) diff --git a/packages/mobile/src/feature/login/login_screen.tsx b/packages/mobile/src/feature/login/login_screen.tsx index 6518e3e..0ca50cc 100644 --- a/packages/mobile/src/feature/login/login_screen.tsx +++ b/packages/mobile/src/feature/login/login_screen.tsx @@ -33,11 +33,6 @@ const LoginScreen = () => { else setLodingState(false) }, [loginData]) - useEffect(() => { - if (loginData?.status == Status?.success) navigation.navigate(RoutePaths.dashboard) - else if (loginData?.status == Status?.error) alert(i18n.t('noInput')) - }, [loginData]) - return ( @@ -51,9 +46,6 @@ const LoginScreen = () => { saveData()} /> - - {i18n.t('forgetPassword')} - ) } diff --git a/packages/mobile/src/feature/login/login_style.ts b/packages/mobile/src/feature/login/login_style.ts index 80db889..cd3bbd5 100644 --- a/packages/mobile/src/feature/login/login_style.ts +++ b/packages/mobile/src/feature/login/login_style.ts @@ -8,7 +8,8 @@ export default StyleSheet.create({ height: Dimensions.get('window').height }, secView: { - width: '100%' + width: '100%', + marginTop: '10%' }, loginText: { fontSize: 24, diff --git a/packages/mobile/src/navigation/app_router.tsx b/packages/mobile/src/navigation/app_router.tsx index cb6c1d1..e4c477c 100644 --- a/packages/mobile/src/navigation/app_router.tsx +++ b/packages/mobile/src/navigation/app_router.tsx @@ -5,15 +5,24 @@ import DashboardScreen from '../feature/dashboard/dashboard_screen' import LoginScreen from '../feature/login/login_screen' import RoutePaths from './router_path' import { useDispatch, useSelector } from 'react-redux' -import { fetchUserExistsAction } from 'presentation' +import { Status, fetchUserExistsAction } from 'presentation' +import SplashScreen from 'react-native-splash-screen' const AppRouter = () => { const Stack = createNativeStackNavigator() - const databaseEmail: any = useSelector((state: any) => state?.userPresentData?.data?.payload) + const databaseEmail: any = useSelector((state: any) => state?.userExistsData) + const logoutData: any = useSelector((state: any) => state?.logout?.data?.payload) + const dispatch = useDispatch() useEffect(() => { dispatch(fetchUserExistsAction({})) }, []) + + useEffect(() => { + if (databaseEmail?.status == Status.success) { + SplashScreen.hide() + } + }, [databaseEmail?.status]) return ( { headerShown: false }} > - {!databaseEmail && } - + {(!databaseEmail?.data?.payload && databaseEmail?.status == Status.success) || logoutData ? ( + + ) : ( + + )} ) diff --git a/packages/mobile/src/widgets/app_button/app_button_style.ts b/packages/mobile/src/widgets/app_button/app_button_style.ts index bfacced..dc97585 100644 --- a/packages/mobile/src/widgets/app_button/app_button_style.ts +++ b/packages/mobile/src/widgets/app_button/app_button_style.ts @@ -6,9 +6,9 @@ export default StyleSheet.create({ buttonView: { alignSelf: 'center', width: '80%', + height: 50, borderRadius: 15, - justifyContent: 'center', - paddingVertical: '5%' + justifyContent: 'center' }, buttonText: { fontSize: 24, diff --git a/packages/presentation/src/feature/login/saga.ts b/packages/presentation/src/feature/login/saga.ts index 42afe60..2f037ab 100644 --- a/packages/presentation/src/feature/login/saga.ts +++ b/packages/presentation/src/feature/login/saga.ts @@ -3,17 +3,21 @@ import { Obsidian } from 'di' import { put } from 'redux-saga/effects' import { LOGIN } from './actions' import { LoginParams } from 'domain-layer' +import { LOGOUT } from '../logout/action' +import { FETCH_USER_EXISTS } from '../userpresent/action' function* loginSaga(action) { const mesage = 'Request failed with status code 403' try { const data: any = yield Obsidian.obtain(DomainModule) - .providesLoginUseCase() + .provideLoginUseCase() .execute(new LoginParams({ email: action?.params?.data?.email, password: action?.params?.data?.password })) if (data == mesage || data == false) { yield put({ type: LOGIN.failure, payload: data }) } else { yield put({ type: LOGIN.success, payload: data }) + yield put({ type: LOGOUT.failure, payload: false }) + yield put({ type: FETCH_USER_EXISTS.success, payload: true }) } } catch (e) { console.log(e) diff --git a/packages/presentation/src/feature/logout/action.ts b/packages/presentation/src/feature/logout/action.ts new file mode 100644 index 0000000..e842691 --- /dev/null +++ b/packages/presentation/src/feature/logout/action.ts @@ -0,0 +1,10 @@ +export enum LOGOUT { + request = 'LOGOUT_REQUEST', + success = 'LOGOUT_SUCCESS', + failure = 'LOGOUT_FAILURE' +} + +export const logoutAction = params => ({ + type: LOGOUT.request, + params +}) diff --git a/packages/presentation/src/feature/logout/reducer.ts b/packages/presentation/src/feature/logout/reducer.ts new file mode 100644 index 0000000..43b485c --- /dev/null +++ b/packages/presentation/src/feature/logout/reducer.ts @@ -0,0 +1,23 @@ +import data from 'packages/data/lib/data' +import { Resource } from '../../utils/resource' +import { LOGOUT } from './action' + +const logoutReducer = (initialState = Resource.none, action) => { + switch (action.type) { + case LOGOUT.request: + return Resource.loading() + + case LOGOUT.success: + return Resource.success({ + data: action + }) + + case LOGOUT.failure: + return Resource.error({ + error: 'User Not logged in' + }) + default: + return initialState + } +} +export default logoutReducer diff --git a/packages/presentation/src/feature/logout/saga.ts b/packages/presentation/src/feature/logout/saga.ts new file mode 100644 index 0000000..d8b6a07 --- /dev/null +++ b/packages/presentation/src/feature/logout/saga.ts @@ -0,0 +1,22 @@ +import { Obsidian } from 'di' +import { put } from 'redux-saga/effects' +import { LogoutParams, DomainModule } from 'domain-layer' +import { LOGOUT } from './action' +import { FETCH_USER_EXISTS } from '../userpresent/action' + +function* logoutSaga(action) { + try { + const data: any = yield Obsidian.obtain(DomainModule) + .provideLogoutUseCase() + .execute(new LogoutParams({ email: action?.params?.databaseEmail })) + if (data == false) { + yield put({ type: LOGOUT.failure, payload: data }) + } else { + yield put({ type: LOGOUT.success, payload: data }) + yield put({ type: FETCH_USER_EXISTS.success, payload: false }) + } + } catch (e) { + console.log(e) + } +} +export default logoutSaga diff --git a/packages/presentation/src/feature/store.ts b/packages/presentation/src/feature/store.ts index 174afd7..9115963 100644 --- a/packages/presentation/src/feature/store.ts +++ b/packages/presentation/src/feature/store.ts @@ -4,13 +4,15 @@ import rootSaga from '../utils/rootSaga' import loginReducer from './login/reducer' import fetchUserReducer from './userDetail/reducer' import fetchUserExistsReducer from './userpresent/reducer' +import logoutReducer from './logout/reducer' const sagaMiddleware = createSagaMiddleware() const store = configureStore({ reducer: combineReducers({ login: loginReducer, userData: fetchUserReducer, - userExistsData: fetchUserExistsReducer + userExistsData: fetchUserExistsReducer, + logout: logoutReducer }), middleware: [sagaMiddleware] }) diff --git a/packages/presentation/src/feature/userDetail/saga.ts b/packages/presentation/src/feature/userDetail/saga.ts index 8e144b7..c2752ac 100644 --- a/packages/presentation/src/feature/userDetail/saga.ts +++ b/packages/presentation/src/feature/userDetail/saga.ts @@ -1,9 +1,8 @@ -import { DomainModule } from 'domain-layer/src/di/domain_module' +import { DomainModule, FetchUserDataUseCaseParams } from 'domain-layer' import { Obsidian } from 'di' import { call, put } from 'redux-saga/effects' import React from 'react' import { FETCH_USER_DATA } from './action' -import { FetchUserDataUseCaseParams } from 'packages/domain/src/domain' function* fetchUserSaga(action) { try { diff --git a/packages/presentation/src/feature/userpresent/saga.ts b/packages/presentation/src/feature/userpresent/saga.ts index ca26bae..bd0affb 100644 --- a/packages/presentation/src/feature/userpresent/saga.ts +++ b/packages/presentation/src/feature/userpresent/saga.ts @@ -1,16 +1,18 @@ -import { DomainModule } from 'domain-layer/src/di/domain_module' +import { DomainModule, FetchUserExistsUseCaseParams } from 'domain-layer' import { Obsidian } from 'di' import { call, put } from 'redux-saga/effects' import React from 'react' import { FETCH_USER_EXISTS } from './action' -import { FetchUserExistsUseCaseParams } from 'packages/domain/src/domain' +import { LOGOUT } from '../logout/action' function* fetchUserExistsSaga(action) { try { const data = yield Obsidian.obtain(DomainModule) .provideUserExistsUseCase() .execute(new FetchUserExistsUseCaseParams({ email: '' })) + console.log(data) yield put({ type: FETCH_USER_EXISTS.success, payload: data }) + yield put({ type: LOGOUT.success, payload: false }) } catch (e) { console.log(e) } diff --git a/packages/presentation/src/presentation.ts b/packages/presentation/src/presentation.ts index 5b03721..3654ee2 100644 --- a/packages/presentation/src/presentation.ts +++ b/packages/presentation/src/presentation.ts @@ -4,5 +4,6 @@ import { loginAction } from './feature/login/actions' import { Resource } from './utils/resource' import store from './feature/store' import { Status } from './utils/status' +import { logoutAction } from './feature/logout/action' -export { store, Status, Resource, loginAction, fetchUserAction, fetchUserExistsAction } +export { store, Status, Resource, loginAction, fetchUserAction, fetchUserExistsAction, logoutAction } diff --git a/packages/presentation/src/utils/rootSaga.ts b/packages/presentation/src/utils/rootSaga.ts index 10fa4ff..d6c90ea 100644 --- a/packages/presentation/src/utils/rootSaga.ts +++ b/packages/presentation/src/utils/rootSaga.ts @@ -5,9 +5,12 @@ import { FETCH_USER_DATA } from '../feature/userDetail/action' import fetchUserSaga from '../feature/userDetail/saga' import { FETCH_USER_EXISTS } from '../feature/userpresent/action' import fetchUserExistsSaga from '../feature/userpresent/saga' +import { LOGOUT } from '../feature/logout/action' +import logoutSaga from '../feature/logout/saga' export default function* rootSaga() { yield takeLatest(LOGIN.request, loginSaga) yield takeLatest(FETCH_USER_DATA.request, fetchUserSaga) yield takeLatest(FETCH_USER_EXISTS.request, fetchUserExistsSaga) + yield takeLatest(LOGOUT.request, logoutSaga) } diff --git a/screenshots/darkTheme.JPEG b/screenshots/darkTheme.JPEG new file mode 100644 index 0000000..b85be32 Binary files /dev/null and b/screenshots/darkTheme.JPEG differ diff --git a/screenshots/dash-darktheme.JPEG b/screenshots/dash-darktheme.JPEG new file mode 100644 index 0000000..db128e2 Binary files /dev/null and b/screenshots/dash-darktheme.JPEG differ diff --git a/screenshots/dash-lightTheme.JPEG b/screenshots/dash-lightTheme.JPEG new file mode 100644 index 0000000..04bb07f Binary files /dev/null and b/screenshots/dash-lightTheme.JPEG differ diff --git a/screenshots/dashboardscreen.png b/screenshots/dashboardscreen.png deleted file mode 100644 index 383fe1d..0000000 Binary files a/screenshots/dashboardscreen.png and /dev/null differ diff --git a/screenshots/lightTheme.JPEG b/screenshots/lightTheme.JPEG new file mode 100644 index 0000000..bc59a55 Binary files /dev/null and b/screenshots/lightTheme.JPEG differ diff --git a/screenshots/loginscreen.png b/screenshots/loginscreen.png deleted file mode 100644 index e3d2d7d..0000000 Binary files a/screenshots/loginscreen.png and /dev/null differ