1 Commits

Author SHA1 Message Date
5c6ec9eda4 removed the selected date on scroll 2024-10-17 21:04:07 +02:00
286 changed files with 29839 additions and 26994 deletions

View File

@ -6,7 +6,15 @@ env:
EXPO_ASC_ISSUER_ID: f7d6175c-75fe-416c-b6d1-0bc9eaf87415
EXPO_APPLE_TEAM_ID: MV9C3PHV87
EXPO_APPLE_TEAM_TYPE: INDIVIDUAL
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
EXPO_TOKEN: qt2h_4xhuhFB-ArysIkzgpsBtWOrrZ-c_So_S9ch
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
@ -14,21 +22,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
cache: yarn
cache: npm
- name: Setup Expo and EAS
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
eas-cache: false
- name: Install dependencies
run: yarn install --immutable
run: npm ci --legacy-peer-deps
- name: Prebuild, Build and Submit
run: yarn prebuild-build-submit-ios-cicd
run: npm run prebuild-build-submit-ios-cicd

1
.gitignore vendored
View File

@ -21,4 +21,3 @@ expo-env.d.ts
/ios/GoogleService-Info.plist
/ios/cally.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
expo-env.d.ts
./android

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxBlameSettings">
<option name="version" value="2" />
</component>
</project>

View File

@ -1,7 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="t" enabled="true" level="TEXT ATTRIBUTES" enabled_by_default="true" editorAttributes="CONSIDERATION_ATTRIBUTES" />
</profile>
</component>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EslintConfiguration">
<option name="fix-on-save" value="true" />
</component>
</project>

View File

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JSHintConfiguration" version="2.13.6" use-config-file="false">
<option asi="false" />
<option bitwise="true" />
<option boss="false" />
<option browser="true" />
<option browserify="false" />
<option camelcase="true" />
<option couch="false" />
<option curly="true" />
<option debug="false" />
<option devel="false" />
<option dojo="false" />
<option elision="false" />
<option enforceall="false" />
<option eqeqeq="true" />
<option eqnull="false" />
<option es3="false" />
<option es5="false" />
<option esnext="false" />
<option evil="false" />
<option expr="false" />
<option forin="true" />
<option freeze="true" />
<option funcscope="false" />
<option futurehostile="false" />
<option gcl="false" />
<option globalstrict="false" />
<option immed="false" />
<option iterator="false" />
<option jasmine="false" />
<option jquery="false" />
<option lastsemic="false" />
<option latedef="false" />
<option laxbreak="false" />
<option laxcomma="false" />
<option loopfunc="false" />
<option maxerr="50" />
<option mocha="false" />
<option module="false" />
<option mootools="false" />
<option moz="false" />
<option multistr="false" />
<option newcap="false" />
<option noarg="true" />
<option nocomma="false" />
<option node="false" />
<option noempty="true" />
<option nomen="false" />
<option nonbsp="false" />
<option nonew="true" />
<option nonstandard="false" />
<option notypeof="false" />
<option noyield="false" />
<option onevar="false" />
<option passfail="false" />
<option phantom="false" />
<option plusplus="false" />
<option proto="false" />
<option prototypejs="false" />
<option qunit="false" />
<option quotmark="false" />
<option rhino="false" />
<option scripturl="false" />
<option shadow="false" />
<option shelljs="false" />
<option singleGroups="false" />
<option smarttabs="false" />
<option strict="true" />
<option sub="false" />
<option supernew="false" />
<option trailing="false" />
<option typed="false" />
<option undef="true" />
<option unused="false" />
<option validthis="false" />
<option varstmt="false" />
<option white="false" />
<option withstmt="false" />
<option worker="false" />
<option wsh="false" />
<option yui="false" />
</component>
</project>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="migrated" value="true" />
<option name="pristineConfig" value="false" />
<option name="userId" value="-7d3b2185:193a8bd7023:-7ffe" />
</MTProjectMetadataState>
</option>
</component>
</project>

View File

@ -1,4 +1,5 @@
apply plugin: "com.android.application"
apply plugin: 'com.google.gms.google-services'
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
@ -20,12 +21,12 @@ react {
bundleCommand = "export:embed"
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../../node_modules/@react-native/codegen")
// The root of your project, i.e. where "package.json" lives. Default is '..'
// root = file("../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
// codegenDir = file("../node_modules/@react-native/codegen")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
@ -57,9 +58,6 @@ react {
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
/* Autolinking */
autolinkLibrariesWithApp()
}
/**
@ -93,6 +91,9 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0.0"
manifestPlaceholders = [
appAuthRedirectScheme: "callyplanner"
]
}
signingConfigs {
debug {
@ -121,9 +122,6 @@ android {
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
}
}
androidResources {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
// Apply static values from `gradle.properties` to the `android.packagingOptions`
@ -175,5 +173,7 @@ dependencies {
}
}
apply plugin: 'com.google.gms.google-services'
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
applyNativeModulesAppBuildGradle(project)
apply plugin: 'com.google.firebase.crashlytics'

View File

@ -1,12 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<queries>
<intent>
@ -15,7 +13,7 @@
<data android:scheme="https"/>
</intent>
</queries>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme">
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="default"/>
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color"/>
<meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
@ -24,7 +22,7 @@
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://u.expo.dev/bdb8c57b-25bb-4d36-b3b8-5b09c5092f52"/>
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode|locale|layoutDirection" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@ -33,10 +31,12 @@
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="callyplanner"/>
<data android:scheme="myapp"/>
<data android:scheme="com.cally.app"/>
<data android:scheme="exp+cally"/>
<data android:scheme="callyplanner"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
</application>
</manifest>

View File

@ -1,5 +1,4 @@
package com.cally.app
import expo.modules.splashscreen.SplashScreenManager
import android.os.Build
import android.os.Bundle
@ -16,10 +15,7 @@ class MainActivity : ReactActivity() {
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
// setTheme(R.style.AppTheme);
// @generated begin expo-splashscreen - expo prebuild (DO NOT MODIFY) sync-f3ff59a738c56c9a6119210cb55f0b613eb8b6af
SplashScreenManager.registerOnActivity(this)
// @generated end expo-splashscreen
setTheme(R.style.AppTheme);
super.onCreate(null)
}

View File

@ -10,7 +10,6 @@ import com.facebook.react.ReactPackage
import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import expo.modules.ApplicationLifecycleDispatcher
@ -22,10 +21,9 @@ class MainApplication : Application(), ReactApplication {
this,
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
val packages = PackageList(this).packages
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages
return PackageList(this).packages
}
override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
@ -42,7 +40,7 @@ class MainApplication : Application(), ReactApplication {
override fun onCreate() {
super.onCreate()
SoLoader.init(this, OpenSourceMergedSoMapping)
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

View File

@ -1,6 +1,3 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/splashscreen_background"/>
<item>
<bitmap android:gravity="center" android:src="@drawable/splashscreen_logo"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,6 +1,6 @@
<resources>
<color name="splashscreen_background">#ffffff</color>
<color name="iconBackground">#FFFFFF</color>
<color name="iconBackground">#ffffff</color>
<color name="colorPrimary">#023c69</color>
<color name="colorPrimaryDark">#ffffff</color>
<color name="notification_icon_color">#ffffff</color>

View File

@ -1,5 +1,5 @@
<resources>
<string name="app_name">\"Cally \"</string>
<string name="app_name">Cally - Family Planner</string>
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
<string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string>
<string name="expo_system_ui_user_interface_style" translatable="false">light</string>

View File

@ -11,9 +11,7 @@
<item name="android:textColorHint">#c8c8c8</item>
<item name="android:textColor">@android:color/black</item>
</style>
<style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splashscreen_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_logo</item>
<item name="postSplashScreenTheme">@style/AppTheme</item>
<style name="Theme.App.SplashScreen" parent="AppTheme">
<item name="android:windowBackground">@drawable/splashscreen</item>
</style>
</resources>

View File

@ -2,11 +2,11 @@
buildscript {
ext {
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '34.0.0'
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '23')
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '34')
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.24'
kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.23'
ndkVersion = "26.1.10909125"
}
@ -16,10 +16,10 @@ buildscript {
}
dependencies {
classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.2'
classpath 'com.google.gms:google-services:4.4.1'
classpath('com.android.tools.build:gradle')
classpath('com.facebook.react:react-native-gradle-plugin')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
classpath('com.google.gms:google-services:4.4.2')
}
}
@ -41,3 +41,7 @@ allprojects {
maven { url 'https://www.jitpack.io' }
}
}
// @generated begin expo-camera-import - expo prebuild (DO NOT MODIFY) sync-f244f4f3d8bf7229102e8f992b525b8602c74770
def expoCameraMavenPath = new File(["node", "--print", "require.resolve('expo-camera/package.json')"].execute(null, rootDir).text.trim(), "../android/maven")
allprojects { repositories { maven { url(expoCameraMavenPath) } } }
// @generated end expo-camera-import

View File

@ -22,6 +22,9 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Enable AAPT2 PNG crunching
android.enablePngCrunchInReleaseBuilds=true

Binary file not shown.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

7
android/gradlew vendored Normal file → Executable file
View File

@ -15,8 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -57,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -86,8 +84,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

2
android/gradlew.bat vendored
View File

@ -13,8 +13,6 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################

View File

@ -1,27 +1,4 @@
pluginManagement {
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile().toString())
}
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
ex.autolinkLibrariesFromCommand()
} else {
def command = [
'node',
'--no-warnings',
'--eval',
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
'react-native-config',
'--json',
'--platform',
'android'
].toList()
ex.autolinkLibrariesFromCommand(command)
}
}
rootProject.name = 'Cally '
rootProject.name = 'Cally - Family Planner'
dependencyResolutionManagement {
versionCatalogs {
@ -34,5 +11,8 @@ dependencyResolutionManagement {
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
useExpoModules()
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
applyNativeModulesSettingsGradle(settings)
include ':app'
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile())

View File

@ -1,10 +1,9 @@
{
"expo": {
"name": "Cally ",
"name": "Cally - Family Planner",
"slug": "cally",
"version": "1.0.0",
"orientation": "portrait",
"owner": "tomira",
"icon": "./assets/images/icon.png",
"scheme": "callyplanner",
"userInterfaceStyle": "light",
@ -17,19 +16,15 @@
"supportsTablet": true,
"bundleIdentifier": "com.cally.app",
"googleServicesFile": "./ios/GoogleService-Info.plist",
"buildNumber": "100",
"usesAppleSignIn": true,
"infoPlist": {
"ITSAppUsesNonExemptEncryption": false
}
"buildNumber": "28"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
"backgroundColor": "#ffffff"
},
"package": "com.cally.app",
"googleServicesFile": "./google-services.json",
"googleServicesFile": "./android/app/google-services.json",
"permissions": [
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO"
@ -68,18 +63,7 @@
"defaultChannel": "default"
}
],
[
"expo-calendar",
{
"calendarPermission": "The app needs to access your calendar."
}
],
[
"expo-apple-authentication"
],
"expo-font",
"expo-localization",
"./plugins/withPodfile"
"expo-font"
],
"experiments": {
"typedRoutes": true

View File

@ -1,356 +1,208 @@
import React, {useCallback} from "react";
import {Drawer} from "expo-router/drawer";
import {DrawerContentScrollView, DrawerContentComponentProps, DrawerNavigationOptions} from "@react-navigation/drawer";
import {ImageBackground, Pressable, StyleSheet} from "react-native";
import {Button, ButtonSize, Text, View} from "react-native-ui-lib";
import * as Device from "expo-device";
import {useSetAtom} from "jotai";
import {Ionicons} from "@expo/vector-icons";
import {DeviceType} from "expo-device";
import {DrawerNavigationProp} from "@react-navigation/drawer";
import {ParamListBase, Theme} from '@react-navigation/native';
import {RouteProp} from "@react-navigation/native";
import {useSignOut} from "@/hooks/firebase/useSignOut";
import {CalendarHeader} from "@/components/pages/calendar/CalendarHeader";
import React from "react";
import { Drawer } from "expo-router/drawer";
import { useSignOut } from "@/hooks/firebase/useSignOut";
import {
DrawerContentScrollView,
DrawerItem,
DrawerItemList,
} from "@react-navigation/drawer";
import { Button, View, Text, ButtonSize } from "react-native-ui-lib";
import { StyleSheet } from "react-native";
import Feather from "@expo/vector-icons/Feather";
import DrawerButton from "@/components/shared/DrawerButton";
import DrawerIcon from "@/assets/svgs/DrawerIcon";
import {
AntDesign,
FontAwesome6,
MaterialCommunityIcons,
Octicons,
} from "@expo/vector-icons";
import MenuIcon from "@/assets/svgs/MenuIcon";
import { router } from "expo-router";
import NavGroceryIcon from "@/assets/svgs/NavGroceryIcon";
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon";
import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
import {
isFamilyViewAtom,
settingsPageIndex,
toDosPageIndex,
userSettingsView,
} from "@/components/pages/calendar/atoms";
import ViewSwitch from "@/components/pages/(tablet_pages)/ViewSwitch";
const isTablet = Device.deviceType === DeviceType.TABLET;
type DrawerParamList = {
index: undefined;
calendar: undefined;
brain_dump: undefined;
settings: undefined;
grocery: undefined;
reminders: undefined;
todos: undefined;
notifications: undefined;
feedback: undefined;
};
type DrawerScreenNavigationProp = DrawerNavigationProp<DrawerParamList>;
interface DrawerButtonConfig {
id: string;
title: string;
color: string;
bgColor: string;
icon: React.FC;
route: keyof DrawerParamList;
}
const DRAWER_BUTTONS: DrawerButtonConfig[] = [
{
id: 'calendar',
title: 'Calendar',
color: 'rgb(7, 184, 199)',
bgColor: 'rgb(231, 248, 250)',
icon: NavCalendarIcon,
route: 'calendar'
},
{
id: 'grocery',
title: 'Groceries',
color: '#50be0c',
bgColor: '#eef9e7',
icon: NavGroceryIcon,
route: 'grocery'
},
{
id: 'feedback',
title: 'Feedback',
color: '#ea156d',
bgColor: '#fdedf4',
icon: FeedbackNavIcon,
route: 'feedback'
},
{
id: 'todos',
title: 'To Dos',
color: '#8005eb',
bgColor: '#f3e6fd',
icon: NavToDosIcon,
route: 'todos'
},
{
id: 'brain_dump',
title: 'Brain Dump',
color: '#e0ca03',
bgColor: '#fffacb',
icon: NavBrainDumpIcon,
route: 'brain_dump'
},
{
id: 'notifications',
title: 'Notifications',
color: '#ffa200',
bgColor: '#ffdda1',
icon: () => <Ionicons name="notifications-outline" size={24} color="#ffa200"/>,
route: 'notifications'
}
];
interface DrawerContentProps {
props: DrawerContentComponentProps;
}
const DrawerContent: React.FC<DrawerContentProps> = ({props}) => {
const {mutateAsync: signOut} = useSignOut();
const setIsFamilyView = useSetAtom(isFamilyViewAtom);
const setPageIndex = useSetAtom(settingsPageIndex);
const setUserView = useSetAtom(userSettingsView);
const setToDosIndex = useSetAtom(toDosPageIndex);
const handleNavigation = useCallback((route: keyof DrawerParamList) => {
props.navigation.navigate(route);
setPageIndex(0);
setToDosIndex(0);
setUserView(true);
setIsFamilyView(false);
}, [props.navigation, setPageIndex, setToDosIndex, setUserView, setIsFamilyView]);
const renderDrawerButtons = () => {
const midPoint = Math.ceil(DRAWER_BUTTONS.length / 2);
const leftButtons = DRAWER_BUTTONS.slice(0, midPoint);
const rightButtons = DRAWER_BUTTONS.slice(midPoint);
export default function TabLayout() {
const { mutateAsync: signOut } = useSignOut();
return (
<Drawer
initialRouteName={"index"}
screenOptions={{
headerShown: true,
drawerStyle: {
width: "90%",
backgroundColor: "#f9f8f7",
height: "100%",
},
drawerIcon: () => <MenuIcon />,
}}
drawerContent={(props) => {
return (
<View row paddingH-30>
<View flex-1 paddingR-5>
{leftButtons.map(button => (
<DrawerButton
key={button.id}
title={button.title}
color={button.color}
bgColor={button.bgColor}
pressFunc={() => handleNavigation(button.route)}
icon={<button.icon/>}
/>
))}
</View>
<View flex-1>
{rightButtons.map(button => (
<DrawerButton
key={button.id}
title={button.title}
color={button.color}
bgColor={button.bgColor}
pressFunc={() => handleNavigation(button.route)}
icon={<button.icon/>}
/>
))}
</View>
<DrawerContentScrollView {...props} style={{ height: "100%" }}>
<View centerH centerV margin-30>
<Text style={styles.title}>Welcome to Cally</Text>
</View>
);
};
return (
<DrawerContentScrollView {...props}>
<View centerV marginH-30 marginT-20 marginB-20 row>
<ImageBackground
source={require("../../assets/images/splash.png")}
style={styles.logo}
<View
style={{
flexDirection: "row",
paddingHorizontal: 30,
}}
>
<View style={{ flex: 1, paddingRight: 5 }}>
<DrawerButton
title={"Calendar"}
color="rgb(7, 184, 199)"
bgColor={"rgb(231, 248, 250)"}
pressFunc={() => props.navigation.navigate("calendar")}
icon={<NavCalendarIcon />}
/>
<Text style={styles.title}>Welcome to Cally</Text>
<DrawerButton
color="#50be0c"
title={"Groceries"}
bgColor={"#eef9e7"}
pressFunc={() => props.navigation.navigate("grocery")}
icon={<NavGroceryIcon />}
/>
</View>
<View style={{ flex: 1 }}>
{/*<DrawerButton
color="#fd1775"
title={"My Reminders"}
bgColor={"#ffe8f2"}
pressFunc={() => props.navigation.navigate("reminders")}
icon={
<FontAwesome6
name="clock-rotate-left"
size={28}
color="#fd1775"
/>
}
/>*/}
<DrawerButton
color="#8005eb"
title={"To Do's"}
bgColor={"#f3e6fd"}
pressFunc={() => props.navigation.navigate("todos")}
icon={<NavToDosIcon />}
/>
<DrawerButton
color="#e0ca03"
title={"Brain Dump"}
bgColor={"#fffacb"}
pressFunc={() => props.navigation.navigate("brain_dump")}
icon={<NavBrainDumpIcon />}
/>
{/*<DrawerItem label="Logout" onPress={() => signOut()} />*/}
</View>
</View>
{renderDrawerButtons()}
<Button
onPress={() => handleNavigation('settings')}
label="Manage Settings"
labelStyle={styles.label}
iconSource={() => (
<View style={styles.settingsIcon}>
<NavSettingsIcon/>
</View>
)}
backgroundColor="white"
color="#464039"
paddingV-30
marginH-30
borderRadius={18.55}
style={{elevation: 0}}
onPress={() => props.navigation.navigate("settings")}
label={"Manage Settings"}
labelStyle={styles.label}
iconSource={() => (
<View
backgroundColor="#ededed"
width={60}
height={60}
style={{ borderRadius: 50 }}
marginR-10
centerV
centerH
>
<NavSettingsIcon />
</View>
)}
backgroundColor="white"
color="#464039"
paddingV-30
marginH-30
marginB-10
borderRadius={18.55}
style={{ elevation: 0 }}
/>
<Button
size={ButtonSize.large}
style={styles.signOutButton}
label="Sign out of Cally"
color="#fd1775"
labelStyle={styles.signOut}
onPress={() => signOut()}
size={ButtonSize.large}
marginH-30
paddingV-15
style={{
marginTop: "42%",
backgroundColor: "transparent",
borderWidth: 1.3,
borderColor: "#fd1775",
}}
label="Sign out of Cally"
color="#fd1775"
labelStyle={styles.signOut}
onPress={() => signOut()}
/>
</DrawerContentScrollView>
);
};
interface HeaderRightProps {
route: RouteProp<DrawerParamList>;
navigation: DrawerScreenNavigationProp;
}
const HeaderRight: React.FC<HeaderRightProps> = ({route, navigation}) => {
const showViewSwitch = ["calendar", "todos", "index"].includes(route.name);
const isCalendarPage = ["calendar", "index"].includes(route.name);
if (!isTablet || !showViewSwitch) {
return isCalendarPage ? <CalendarHeader/> : null;
}
return (
<View marginR-16 row centerV>
{isTablet && isCalendarPage && (
<View flex-1 center>
<CalendarHeader/>
</View>
)}
<ViewSwitch navigation={navigation}/>
</View>
);
};
const screenOptions: (props: {
route: RouteProp<ParamListBase, string>;
navigation: DrawerNavigationProp<ParamListBase, string>;
theme: Theme;
}) => DrawerNavigationOptions = ({route, navigation}) => ({
lazy: true,
headerShown: true,
headerTitleAlign: "left",
headerTitle: ({children}) => {
const isCalendarRoute = ["calendar", "index"].includes(route.name);
if (isCalendarRoute) return null;
return (
<View flexG centerV paddingL-10>
<Text style={styles.headerTitle}>
{children}
</Text>
</View>
</DrawerContentScrollView>
);
},
headerLeft: () => (
<Pressable
onPress={() => navigation.toggleDrawer()}
hitSlop={{top: 10, bottom: 10, left: 10, right: 10}}
style={({pressed}) => [styles.drawerTrigger, {opacity: pressed ? 0.4 : 1}]}
>
<DrawerIcon/>
</Pressable>
),
headerRight: () => <HeaderRight
route={route as RouteProp<DrawerParamList>}
navigation={navigation as DrawerNavigationProp<DrawerParamList>}
/>,
drawerStyle: styles.drawer,
});
interface DrawerScreen {
name: keyof DrawerParamList;
title: string;
hideInDrawer?: boolean;
}}
>
<Drawer.Screen
name="index"
options={{
drawerLabel: "Calendar",
title: "Calendar",
}}
/>
<Drawer.Screen
name="calendar"
options={{
drawerLabel: "Calendar",
title: "Calendar",
drawerItemStyle: { display: "none" },
}}
/>
<Drawer.Screen
name="brain_dump"
options={{
drawerLabel: "Brain Dump",
title: "Brain Dump",
}}
/>
<Drawer.Screen
name="settings"
options={{
drawerLabel: "Settings",
title: "Settings",
}}
/>
<Drawer.Screen
name="grocery"
options={{
drawerLabel: "Grocery",
title: "Grocery",
}}
/>
<Drawer.Screen
name="reminders"
options={{
drawerLabel: "Reminders",
title: "Reminders",
}}
/>
<Drawer.Screen
name="todos"
options={{
drawerLabel: "To-Do",
title: "To-Do's",
}}
/>
</Drawer>
);
}
const DRAWER_SCREENS: DrawerScreen[] = [
{name: 'index', title: 'Calendar'},
{name: 'calendar', title: 'Calendar', hideInDrawer: true},
{name: 'brain_dump', title: 'Brain Dump'},
{name: 'settings', title: 'Settings'},
{name: 'grocery', title: 'Groceries'},
{name: 'reminders', title: 'Reminders'},
{name: 'todos', title: isTablet ? 'Family To Dos' : 'To Dos'},
{name: 'notifications', title: 'Notifications'},
{name: 'feedback', title: 'Feedback'}
];
const TabLayout: React.FC = () => {
return (
<Drawer
initialRouteName="index"
detachInactiveScreens
screenOptions={screenOptions}
drawerContent={(props) => <DrawerContent props={props}/>}
>
{DRAWER_SCREENS.map(screen => (
<Drawer.Screen
key={screen.name}
name={screen.name}
options={{
drawerLabel: screen.title,
title: screen.title,
...(screen.hideInDrawer && {drawerItemStyle: {display: 'none'}}),
}}
/>
))}
</Drawer>
);
};
const styles = StyleSheet.create({
drawer: {
width: isTablet ? "30%" : "90%",
backgroundColor: "#f9f8f7",
height: "100%",
},
drawerTrigger: {
marginLeft: 16,
},
headerTitle: {
fontFamily: "Manrope_600SemiBold",
fontSize: isTablet ? 22 : 17,
},
logo: {
backgroundColor: "transparent",
height: 51.43,
aspectRatio: 1,
marginRight: 8,
},
settingsIcon: {
backgroundColor: "#ededed",
width: 60,
height: 60,
borderRadius: 50,
marginRight: 10,
justifyContent: 'center',
alignItems: 'center',
},
signOutButton: {
marginTop: 50,
marginHorizontal: 10,
paddingVertical: 15,
backgroundColor: "transparent",
borderWidth: 1.3,
borderColor: "#fd1775",
},
signOut: {
fontFamily: "Poppins_500Medium",
fontSize: 15,
},
label: {
fontFamily: "Poppins_400Medium",
fontSize: 15,
},
title: {
fontSize: 26.13,
fontFamily: "Manrope_600SemiBold",
color: "#262627",
},
signOut: { fontFamily: "Poppins_500Medium", fontSize: 15 },
label: { fontFamily: "Poppins_400Medium", fontSize: 15 },
title: {
fontSize: 26.13,
fontFamily: 'Manrope_600SemiBold',
color: "#262627"
}
});
export default TabLayout;

View File

@ -1,13 +1,14 @@
import {BrainDumpProvider} from "@/contexts/DumpContext";
import {View} from "react-native-ui-lib";
import BrainDumpPage from "@/components/pages/brain_dump/BrainDumpPage";
import { BrainDumpProvider } from "@/contexts/DumpContext";
import { ScrollView } from "react-native-gesture-handler";
import { View } from "react-native-ui-lib";
export default function Screen() {
return (
<BrainDumpProvider>
<View>
<BrainDumpPage/>
</View>
</BrainDumpProvider>
);
return (
<BrainDumpProvider>
<View>
<BrainDumpPage />
</View>
</BrainDumpProvider>
);
}

View File

@ -1,92 +1,14 @@
import React, {useEffect} from "react";
import {RefreshControl, ScrollView, View} from "react-native";
import React from "react";
import { CalendarProvider } from "@/contexts/CalendarContext"; // Import the new CalendarPage component
import CalendarPage from "@/components/pages/calendar/CalendarPage";
import TabletCalendarPage from "@/components/pages/(tablet_pages)/calendar/TabletCalendarPage";
import * as Device from "expo-device";
import {DeviceType} from "expo-device";
import {useCalSync} from "@/hooks/useCalSync";
import {colorMap} from "@/constants/colorMap";
import {useSetAtom} from "jotai";
import {selectedUserAtom} from "@/components/pages/calendar/atoms";
import {useAuthContext} from "@/contexts/AuthContext";
import { SettingsContextProvider } from "@/contexts/SettingsContext";
export default function Screen() {
const isTablet = Device.deviceType === DeviceType.TABLET;
const {resyncAllCalendars, isSyncing} = useCalSync();
const setSelectedUser = useSetAtom(selectedUserAtom);
const {profileData} = useAuthContext()
useEffect(() => {
if (!isTablet && profileData) setSelectedUser({
uid: profileData.uid!,
firstName: profileData.firstName,
lastName: profileData.lastName,
eventColor: profileData?.eventColor!
})
}, [])
const onRefresh = React.useCallback(async () => {
try {
await resyncAllCalendars();
} catch (error) {
console.error("Refresh failed:", error);
}
}, [resyncAllCalendars]);
const refreshControl = (
<RefreshControl
colors={[
colorMap.pink,
colorMap.green,
colorMap.orange,
colorMap.purple,
colorMap.teal,
]}
tintColor={colorMap.pink}
progressBackgroundColor="white"
refreshing={isSyncing}
onRefresh={onRefresh}
style={isTablet ? {
position: "absolute",
left: "50%",
transform: [{translateX: -20}],
} : undefined}
/>
);
if (isTablet) {
return (
<View style={{flex: 1}}>
<View style={{flex: 1, zIndex: 0}}>
<TabletCalendarPage/>
</View>
<ScrollView
style={{
position: "absolute",
top: 0,
left: "15%",
height: "9%",
width: "62%",
zIndex: 50,
backgroundColor: "transparent",
}}
contentContainerStyle={{
flex: 1,
justifyContent: "center",
paddingRight: 200,
}}
bounces={true}
showsVerticalScrollIndicator={false}
pointerEvents={isSyncing ? "auto" : "none"}
/>
</View>
);
}
return (
<View style={{flex: 1}}>
<CalendarPage/>
</View>
);
}
return (
<SettingsContextProvider>
<CalendarProvider>
<CalendarPage />
</CalendarProvider>
</SettingsContextProvider>
);
}

View File

@ -1,5 +0,0 @@
import {Stack} from "expo-router";
export default function StackLayout () {
return <Stack screenOptions={{headerShown: false}}/>
}

View File

@ -1,13 +0,0 @@
import FeedbackPage from "@/components/pages/feedback/FeedbackPage";
import { FeedbackProvider } from "@/contexts/FeedbackContext";
import { View } from "react-native-ui-lib";
export default function Screen() {
return (
<FeedbackProvider>
<View>
<FeedbackPage />
</View>
</FeedbackProvider>
);
}

View File

@ -1,5 +0,0 @@
import {Stack} from "expo-router";
export default function StackLayout () {
return <Stack screenOptions={{headerShown: false}}/>
}

View File

@ -1,7 +0,0 @@
import NotificationsPage from "@/components/pages/notifications/NotificationsPage";
export default function Screen() {
return (
<NotificationsPage/>
);
}

View File

@ -1,8 +1,11 @@
import SettingsPage from "@/components/pages/settings/SettingsPage";
import {SettingsContextProvider} from "@/contexts/SettingsContext";
import React from "react";
export default function Screen() {
return (
<SettingsPage/>
<SettingsContextProvider>
<SettingsPage/>
</SettingsContextProvider>
);
}

View File

@ -1,16 +1,19 @@
import TabletChoresPage from "@/components/pages/(tablet_pages)/chores/TabletChoresPage";
import AddChore from "@/components/pages/todos/AddChore";
import ProgressCard from "@/components/pages/todos/ProgressCard";
import ToDoItem from "@/components/pages/todos/ToDoItem";
import ToDosList from "@/components/pages/todos/ToDosList";
import ToDosPage from "@/components/pages/todos/ToDosPage";
import {ToDosContextProvider} from "@/contexts/ToDosContext";
import * as Device from "expo-device";
import HeaderTemplate from "@/components/shared/HeaderTemplate";
import { useAuthContext } from "@/contexts/AuthContext";
import { ToDosContextProvider, useToDosContext } from "@/contexts/ToDosContext";
import { AntDesign } from "@expo/vector-icons";
import { ScrollView } from "react-native-gesture-handler";
import { Button, ButtonSize, View, Text } from "react-native-ui-lib";
export default function Screen() {
return (
<ToDosContextProvider>
{Device.deviceType === Device.DeviceType.TABLET ? (
<TabletChoresPage/>
) : (
<ToDosPage/>
)}
</ToDosContextProvider>
);
return (
<ToDosContextProvider>
<ToDosPage />
</ToDosContextProvider>
);
}

View File

@ -1,117 +0,0 @@
import { SafeAreaView } from "react-native-safe-area-context";
import { Button, Text, View, DateTimePicker } from "react-native-ui-lib";
import React, { useState } from "react";
import { useRouter } from "expo-router";
import { Platform, StyleSheet } from "react-native";
import { useAuthContext } from "@/contexts/AuthContext";
import firestore from "@react-native-firebase/firestore";
import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
export default function BirthdayScreen() {
const router = useRouter();
const { user } = useAuthContext();
const [date, setDate] = useState(new Date());
const { mutateAsync: updateUserData } = useUpdateUserData();
const onDateChange = (event: any, selectedDate?: Date) => {
const currentDate = selectedDate || date;
setDate(currentDate);
};
const handleContinue = async () => {
try {
updateUserData({
newUserData: {
birthday: date,
},
}).then(() => router.push("/(unauth)/cal_sync"));
} catch (error) {
console.error("Error saving birthday:", error);
}
};
const getMaxDate = () => {
const date = new Date();
date.setFullYear(date.getFullYear() - 3); // Minimum age: 3 years
return date;
};
const getMinDate = () => {
const date = new Date();
date.setFullYear(date.getFullYear() - 18); // Maximum age: 18 years
return date;
};
return (
<SafeAreaView style={{ flex: 1 }}>
<View
style={{
flex: 1,
padding: 21,
paddingBottom: 45,
paddingTop: "20%",
alignItems: "center",
}}
>
<View gap-13 width={"100%"} marginB-20>
<Text style={{ fontSize: 40, fontFamily: "Manrope_600SemiBold" }}>
When's your birthday?
</Text>
<Text color={"#919191"} style={{ fontSize: 20 }}>
We'll use this to celebrate your special day!
</Text>
</View>
<View width={"100%"} flexG>
<DateTimePicker
value={date}
mode="date"
minimumDate={getMinDate()}
maximumDate={getMaxDate()}
onChange={(date) => {
if (date) {
const validDate = new Date(date);
if (!isNaN(validDate.getTime())) {
setDate(validDate);
}
}
}}
style={styles.textfield}
textAlign="center"
/>
</View>
<View flexG />
<View width={"100%"}>
<Button
label="Continue"
onPress={handleContinue}
style={{
height: 50,
}}
backgroundColor="#fd1775"
labelStyle={{
fontFamily: "PlusJakartaSans_600SemiBold",
fontSize: 16,
}}
/>
</View>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
textfield: {
backgroundColor: "white",
marginVertical: 100,
padding: 30,
height: 44,
borderRadius: 50,
fontFamily: "PlusJakartaSans_300Light",
fontSize: 15,
color: "#919191",
alignContent: "center",
},
});

View File

@ -1,256 +0,0 @@
import {SafeAreaView} from "react-native-safe-area-context";
import {Button, Text, View} from "react-native-ui-lib";
import React, { useEffect } from "react";
import {useCalSync} from "@/hooks/useCalSync";
import GoogleIcon from "@/assets/svgs/GoogleIcon";
import AppleIcon from "@/assets/svgs/AppleIcon";
import OutlookIcon from "@/assets/svgs/OutlookIcon";
import {useAuthContext} from "@/contexts/AuthContext";
import {StyleSheet} from "react-native";
import { useGetHouseholdName } from "@/hooks/firebase/useGetHouseholdName";
export default function Screen() {
const {profileData, setRedirectOverride} = useAuthContext()
const {handleStartGoogleSignIn, handleAppleSignIn, handleMicrosoftSignIn} = useCalSync()
const {data: householdName, refetch} = useGetHouseholdName(profileData?.familyId);
useEffect(() => {
refetch();
}, [profileData?.familyId])
const hasSomeCalendarsSynced =
!!profileData?.appleAccounts || !!profileData?.microsoftAccounts || !!profileData?.googleAccounts
return (
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 1, padding: 21, paddingBottom: 45, paddingTop: "20%", alignItems: "center"}}>
<View gap-13 width={"100%"} marginB-20>
{householdName && <Text style={{fontSize: 25, fontFamily: 'Manrope_600SemiBold'}}>
You Joined The {householdName} Household
</Text>}
<Text style={{fontSize: 40, fontFamily: 'Manrope_600SemiBold'}}>
Let's get started!
</Text>
<Text color={"#919191"} style={{fontSize: 20}}>
Add your calendar below to sync events to your Cally calendar
</Text>
</View>
<View width={"100%"} gap-1>
{!profileData?.googleAccounts && (
<Button
onPress={() => handleStartGoogleSignIn()}
label={"Connect Google account"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<GoogleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)}
{profileData?.googleAccounts
? Object.keys(profileData?.googleAccounts)?.map((googleMail) => {
const googleToken = profileData?.googleAccounts?.[googleMail]?.accessToken;
return (
googleToken && (
<Button
key={googleMail}
disabled
label={`Connected ${googleMail}`}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<GoogleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)
);
})
: null}
{!profileData?.appleAccounts && (
<Button
onPress={() => handleAppleSignIn()}
label={"Connect Apple"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<AppleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)}
{profileData?.appleAccounts
? Object.keys(profileData?.appleAccounts)?.map((appleEmail) => {
const appleToken = profileData?.appleAccounts?.[appleEmail!];
return (
appleToken && (
<Button
key={appleEmail}
disabled
label={`Connected Apple Calendar`}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<AppleIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)
);
})
: null}
{!profileData?.microsoftAccounts && (
<Button
onPress={() => handleMicrosoftSignIn()}
label={"Connect Outlook"}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<OutlookIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)}
{profileData?.microsoftAccounts
? Object.keys(profileData?.microsoftAccounts)?.map(
(microsoftEmail) => {
const microsoftToken =
profileData?.microsoftAccounts?.[microsoftEmail];
return (
microsoftToken && (
<Button
key={microsoftEmail}
label={`Connected ${microsoftEmail}`}
labelStyle={styles.addCalLbl}
labelProps={{
numberOfLines: 2,
}}
iconSource={() => (
<View marginR-15>
<OutlookIcon/>
</View>
)}
style={styles.addCalBtn}
color="black"
text70BL
/>
)
);
}
)
: null}
</View>
<View flexG/>
<View width={"100%"}>
<Button
label={hasSomeCalendarsSynced ? "Continue" : "Skip this step"}
onPress={() => setRedirectOverride(false)}
marginT-50
labelStyle={{
fontFamily: "PlusJakartaSans_600SemiBold",
fontSize: 16,
}}
style={{height: 50}}
backgroundColor="#fd1775"
/>
</View>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
addCalBtn: {
backgroundColor: "#ffffff",
marginBottom: 15,
justifyContent: "flex-start",
paddingLeft: 25,
},
backBtn: {
backgroundColor: "red",
marginLeft: -2,
justifyContent: "flex-start",
},
card: {
backgroundColor: "white",
width: "100%",
padding: 20,
paddingBottom: 30,
marginTop: 20,
borderRadius: 12,
},
noPaddingCard: {
backgroundColor: "white",
width: "100%",
marginTop: 20,
borderRadius: 12,
},
colorBox: {
aspectRatio: 1,
justifyContent: "center",
alignItems: "center",
width: 51,
borderRadius: 12,
},
checkbox: {
borderRadius: 50,
},
addCalLbl: {
fontSize: 16,
fontFamily: "PlusJakartaSan_500Medium",
flexWrap: "wrap",
width: "75%",
textAlign: "left",
lineHeight: 20,
overflow: "visible",
},
subTitle: {
fontFamily: "Manrope_600SemiBold",
fontSize: 18,
},
cardTitle: {
fontFamily: "Manrope_500Medium",
fontSize: 15,
},
});

View File

@ -1,229 +0,0 @@
import { SafeAreaView } from "react-native-safe-area-context";
import {
Button,
Colors,
Dialog,
LoaderScreen,
Text,
View,
} from "react-native-ui-lib";
import React, { useCallback, useEffect, useState } from "react";
import { useRouter } from "expo-router";
import QRIcon from "@/assets/svgs/QRIcon";
import { Camera, CameraView } from "expo-camera";
import { useLoginWithQrCode } from "@/hooks/firebase/useLoginWithQrCode";
import { useAuthContext } from "@/contexts/AuthContext";
import debounce from "debounce";
import * as Device from "expo-device";
import { DeviceType } from "expo-device";
import { Dimensions } from "react-native";
export default function Screen() {
const router = useRouter();
const { setRedirectOverride } = useAuthContext();
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [showCameraDialog, setShowCameraDialog] = useState<boolean>(false);
const isTablet: boolean = Device.deviceType === DeviceType.TABLET;
const [isPortrait, setIsPortrait] = useState(() => {
const dim = Dimensions.get('screen');
return dim.height >= dim.width;
});
useEffect(() => {
const subscription = Dimensions.addEventListener('change', ({ screen }) => {
setIsPortrait(screen.height >= screen.width);
});
return () => subscription.remove();
}, []);
const getTopPadding = () => {
if (Device.deviceType === DeviceType.TABLET) {
return isPortrait ? "50%" : "15%";
}
return "20%"; // non-tablet case, regardless of orientation
};
const { mutateAsync: signInWithQrCode, isLoading } = useLoginWithQrCode();
const debouncedRouterReplace = useCallback(
debounce(() => {
router.push("/(unauth)/birthday_page");
}, 300),
[]
);
const handleQrCodeScanned = async ({ data }: { data: string }) => {
setShowCameraDialog(false);
setRedirectOverride(true);
try {
await signInWithQrCode({ userId: data });
debouncedRouterReplace();
} catch (err) {
console.log(err);
}
};
const getCameraPermissions = async (callback: () => void) => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === "granted");
if (status === "granted") {
callback();
}
};
const handleOpenQrCodeDialog = () => {
getCameraPermissions(() => setShowCameraDialog(true));
};
return (
<SafeAreaView style={{ flex: 1, alignItems: "center" }}>
<View
style={{
flex: 1,
padding: 21,
paddingBottom: 45,
paddingTop: isLoading ? "20%" : getTopPadding(),
width: isTablet ? 629 : '100%'
}}
>
<View center>
<Text style={{ fontSize: 30, fontFamily: "Manrope_600SemiBold" }}>
Get started with Cally
</Text>
</View>
<View width={"100%"} gap-30>
<View>
<Button
label="Scan QR Code"
marginT-50
labelStyle={{
fontFamily: "PlusJakartaSans_400Regular",
fontSize: 16,
marginLeft: 10,
}}
iconSource={() => <QRIcon color={"#07B8C7"} />}
onPress={handleOpenQrCodeDialog}
style={{ height: 50 }}
color={Colors.black}
backgroundColor={Colors.white}
/>
{/* GOOGLE LOGIN HERE */}
</View>
<View row center gap-20>
<View flexG style={{ backgroundColor: "#E2E2E2", height: 2 }} />
<Text
style={{
fontSize: 16,
fontFamily: "PlusJakartaSans_300Light",
color: "#7A7A7A",
}}
>
or
</Text>
<View flexG style={{ backgroundColor: "#E2E2E2", height: 2 }} />
</View>
<View>
<Button
label="Continue with Email"
labelStyle={{
fontFamily: "PlusJakartaSans_400Regular",
fontSize: 16,
marginLeft: 10,
}}
onPress={() => router.push("/(unauth)/sign_up")}
style={{
height: 50,
borderStyle: "solid",
borderColor: "#E2E2E2",
borderWidth: 2,
}}
color={Colors.black}
backgroundColor={"transparent"}
/>
</View>
</View>
{isTablet ? (
<View marginT-30 />
) : (
<View flexG />
)}
<View row centerH gap-5>
<Text
style={{
fontFamily: "PlusJakartaSans_300Light",
fontSize: 16,
color: "#484848",
}}
center
>
Already have an account?
</Text>
<Button
label="Log in"
link
onPress={() => router.push("/(unauth)/sign_in")}
labelStyle={[
{
fontFamily: "PlusJakartaSans_500Medium",
fontSize: 16,
color: "#919191",
},
{ fontSize: 16, textDecorationLine: "none", color: "#fd1775" },
]}
/>
</View>
</View>
{/* Legacy, move into separate component */}
{/* Camera Dialog */}
<Dialog
visible={showCameraDialog}
onDismiss={() => setShowCameraDialog(false)}
bottom
width="100%"
height="70%"
containerStyle={{ padding: 15, backgroundColor: "white" }}
>
<Text center style={{ fontSize: 16 }} marginB-15>
Scan a QR code presented from your family member of provider.
</Text>
{hasPermission === null ? (
<Text>Requesting camera permissions...</Text>
) : !hasPermission ? (
<Text>No access to camera</Text>
) : (
<CameraView
style={{ flex: 1, borderRadius: 15 }}
onBarcodeScanned={handleQrCodeScanned}
barcodeScannerSettings={{
barcodeTypes: ["qr"],
}}
/>
)}
<Button
label="Cancel"
onPress={() => setShowCameraDialog(false)}
backgroundColor="#fd1775"
style={{ margin: 10, marginBottom: 30 }}
/>
</Dialog>
{isLoading && (
<LoaderScreen
overlay
message={"Signing in..."}
backgroundColor={Colors.white}
color={Colors.grey40}
/>
)}
</SafeAreaView>
);
}

View File

@ -1,46 +1,10 @@
import Entry from "@/components/pages/main/Entry";
import {SafeAreaView} from "react-native-safe-area-context";
import {Button, Image, Text, View} from "react-native-ui-lib";
import React from "react";
import {useRouter} from "expo-router";
import * as Device from "expo-device";
import { DeviceType } from "expo-device";
export default function Screen() {
const router = useRouter()
return (
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 1, padding: 21, paddingBottom: 45, paddingTop: "20%", alignItems: "center"}}>
<View>
<Image source={require("../../assets/images/splash.png")}/>
</View>
<View center gap-13>
<Text style={{fontSize: 40, fontFamily: 'Manrope_600SemiBold', marginLeft: 5}}>
Welcome to Cally
</Text>
<Text center color={"#919191"} style={{fontSize: 20, maxWidth: 250}}>
Lightening Mental Loads,
One Family at a Time
</Text>
</View>
<View flexG/>
<View width={"100%"} centerH>
<Button
label="Continue"
marginT-50
labelStyle={{
fontFamily: "PlusJakartaSans_600SemiBold",
fontSize: 16,
}}
onPress={() => router.push("/(unauth)/get_started")}
style={{height: 50, width: Device.deviceType === DeviceType.TABLET ? 629 : "100%"}}
backgroundColor="#fd1775"
/>
</View>
</View>
<SafeAreaView>
<Entry/>
</SafeAreaView>
)
}
}

View File

View File

@ -1,5 +1,5 @@
import Entry from "@/components/pages/main/Entry";
export default function Screen() {
return <Entry />;
return <Entry />;
}

View File

@ -1,6 +0,0 @@
import React from "react";
import {ResetPasswordPage} from "@/components/pages/main/ResetPasswordPage";
export default function Screen() {
return <ResetPasswordPage/>
}

View File

@ -1,6 +0,0 @@
import SignInPage from "@/components/pages/main/SignInPage";
import React from "react";
export default function Screen() {
return <SignInPage/>
}

View File

@ -1,8 +0,0 @@
import React from "react";
import SignUpPage from "@/components/pages/main/SignUpPage";
export default function Screen() {
return (
<SignUpPage/>
)
}

View File

@ -1,6 +1,170 @@
import React, {useEffect} from "react";
import {DefaultTheme, ThemeProvider} from "@react-navigation/native";
import React, { useEffect } from "react";
import { DefaultTheme, ThemeProvider } from "@react-navigation/native";
import {
useFonts,
Manrope_200ExtraLight,
Manrope_300Light,
Manrope_400Regular,
Manrope_500Medium,
Manrope_600SemiBold,
Manrope_700Bold,
Manrope_800ExtraBold,
} from "@expo-google-fonts/manrope";
import {
PlusJakartaSans_200ExtraLight,
PlusJakartaSans_300Light,
PlusJakartaSans_400Regular,
PlusJakartaSans_500Medium,
PlusJakartaSans_600SemiBold,
PlusJakartaSans_700Bold,
PlusJakartaSans_800ExtraBold,
PlusJakartaSans_200ExtraLight_Italic,
PlusJakartaSans_300Light_Italic,
PlusJakartaSans_400Regular_Italic,
PlusJakartaSans_500Medium_Italic,
PlusJakartaSans_600SemiBold_Italic,
PlusJakartaSans_700Bold_Italic,
PlusJakartaSans_800ExtraBold_Italic,
} from "@expo-google-fonts/plus-jakarta-sans";
import {
Poppins_100Thin,
Poppins_100Thin_Italic,
Poppins_200ExtraLight,
Poppins_200ExtraLight_Italic,
Poppins_300Light,
Poppins_300Light_Italic,
Poppins_400Regular,
Poppins_400Regular_Italic,
Poppins_500Medium,
Poppins_500Medium_Italic,
Poppins_600SemiBold,
Poppins_600SemiBold_Italic,
Poppins_700Bold,
Poppins_700Bold_Italic,
Poppins_800ExtraBold,
Poppins_800ExtraBold_Italic,
Poppins_900Black,
Poppins_900Black_Italic,
} from "@expo-google-fonts/poppins";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import "react-native-reanimated";
import { AuthContextProvider } from "@/contexts/AuthContext";
import { QueryClient, QueryClientProvider } from "react-query";
import {
ThemeManager,
Typography,
Toast,
TextProps,
} from "react-native-ui-lib";
import functions from "@react-native-firebase/functions";
import auth from "@react-native-firebase/auth";
import firestore from "@react-native-firebase/firestore";
SplashScreen.preventAutoHideAsync();
const queryClient = new QueryClient();
if (__DEV__) {
functions().useEmulator("localhost", 5001);
firestore().useEmulator("localhost", 5471);
auth().useEmulator("http://localhost:9099");
}
type TextStyleBase =
| "text10"
| "text20"
| "text30"
| "text40"
| "text50"
| "text60"
| "text70"
| "text80"
| "text90"
| "text100";
type TextStyleModifier = "R" | "M" | "BO" | "H" | "BL" | "L";
type TextStyle = TextStyleBase | `${TextStyleBase}${TextStyleModifier}`;
type TextStyleProps = {
[K in TextStyle]?: boolean;
};
type ExtendedTextProps = TextProps & TextStyleProps;
interface FontStyle {
fontFamily: string;
fontSize: number;
}
const getManropeFontStyle = (style: TextStyle): FontStyle => {
let fontFamily: string;
let fontSize: number;
if (style.includes("L") || style.includes("BL"))
fontFamily = "Manrope_300Light";
else if (style.includes("R")) fontFamily = "Manrope_400Regular";
else if (style.includes("M")) fontFamily = "Manrope_500Medium";
else if (style.includes("BO") || style.includes("H"))
fontFamily = "Manrope_700Bold";
else {
const baseStyle = style.slice(0, 6) as TextStyleBase;
switch (baseStyle) {
case "text10":
case "text20":
fontFamily = "Manrope_700Bold";
break;
case "text30":
case "text40":
fontFamily = "Manrope_600SemiBold";
break;
case "text50":
fontFamily = "Manrope_400Regular";
break;
default:
fontFamily = "Manrope_300Light";
}
}
switch (style.slice(0, 6) as TextStyleBase) {
case "text10":
fontSize = 64;
break;
case "text20":
fontSize = 50;
break;
case "text30":
fontSize = 36;
break;
case "text40":
fontSize = 28;
break;
case "text50":
fontSize = 24;
break;
case "text60":
fontSize = 20;
break;
case "text70":
fontSize = 16;
break;
case "text80":
fontSize = 14;
break;
case "text90":
fontSize = 12;
break;
case "text100":
fontSize = 10;
break;
default:
fontSize = 16;
}
return { fontFamily, fontSize };
};
export default function RootLayout() {
const [loaded] = useFonts({
Manrope_200ExtraLight,
Manrope_300Light,
Manrope_400Regular,
@ -8,25 +172,20 @@ import {
Manrope_600SemiBold,
Manrope_700Bold,
Manrope_800ExtraBold,
useFonts,
} from "@expo-google-fonts/manrope";
import {
PlusJakartaSans_200ExtraLight,
PlusJakartaSans_200ExtraLight_Italic,
PlusJakartaSans_300Light,
PlusJakartaSans_300Light_Italic,
PlusJakartaSans_400Regular,
PlusJakartaSans_400Regular_Italic,
PlusJakartaSans_500Medium,
PlusJakartaSans_500Medium_Italic,
PlusJakartaSans_600SemiBold,
PlusJakartaSans_600SemiBold_Italic,
PlusJakartaSans_700Bold,
PlusJakartaSans_700Bold_Italic,
PlusJakartaSans_800ExtraBold,
PlusJakartaSans_200ExtraLight_Italic,
PlusJakartaSans_300Light_Italic,
PlusJakartaSans_400Regular_Italic,
PlusJakartaSans_500Medium_Italic,
PlusJakartaSans_600SemiBold_Italic,
PlusJakartaSans_700Bold_Italic,
PlusJakartaSans_800ExtraBold_Italic,
} from "@expo-google-fonts/plus-jakarta-sans";
import {
Poppins_100Thin,
Poppins_100Thin_Italic,
Poppins_200ExtraLight,
@ -45,230 +204,72 @@ import {
Poppins_800ExtraBold_Italic,
Poppins_900Black,
Poppins_900Black_Italic,
} from "@expo-google-fonts/poppins";
import {Stack} from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import "react-native-reanimated";
import {AuthContextProvider} from "@/contexts/AuthContext";
import {TextProps, ThemeManager, Toast, Typography,} from "react-native-ui-lib";
import {Platform} from 'react-native';
import KeyboardManager from 'react-native-keyboard-manager';
import {enableScreens, enableFreeze} from 'react-native-screens';
import {PersistQueryClientProvider} from "@/contexts/PersistQueryClientProvider";
});
enableScreens(true)
enableFreeze(true)
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
SplashScreen.preventAutoHideAsync();
const typographies: Partial<Record<TextStyle, FontStyle>> = {};
(
[
"text10",
"text20",
"text30",
"text40",
"text50",
"text60",
"text70",
"text80",
"text90",
"text100",
] as const
).forEach((baseStyle) => {
typographies[baseStyle] = getManropeFontStyle(baseStyle);
(["R", "M", "BO", "H", "BL", "L"] as const).forEach((modifier) => {
const style = `${baseStyle}${modifier}` as TextStyle;
typographies[style] = getManropeFontStyle(style);
});
});
if (Platform.OS === 'ios') {
KeyboardManager.setEnable(true);
KeyboardManager.setToolbarPreviousNextButtonEnable(true);
}
Typography.loadTypographies(typographies);
if (__DEV__) {
// functions().useEmulator("localhost", 5001);
// firestore().useEmulator("localhost", 5471);
// auth().useEmulator("http://localhost:9099");
}
ThemeManager.setComponentTheme(
"Text",
(props: ExtendedTextProps, context: unknown) => {
const textStyle = (
Object.keys(props) as Array<keyof ExtendedTextProps>
).find((key) => typographies[key as TextStyle]) as
| TextStyle
| undefined;
type TextStyleBase =
| "text10"
| "text20"
| "text30"
| "text40"
| "text50"
| "text60"
| "text70"
| "text80"
| "text90"
| "text100";
type TextStyleModifier = "R" | "M" | "BO" | "H" | "BL" | "L";
type TextStyle = TextStyleBase | `${TextStyleBase}${TextStyleModifier}`;
type TextStyleProps = {
[K in TextStyle]?: boolean;
};
type ExtendedTextProps = TextProps & TextStyleProps;
interface FontStyle {
fontFamily: string;
fontSize: number;
}
const getManropeFontStyle = (style: TextStyle): FontStyle => {
let fontFamily: string;
let fontSize: number;
if (style.includes("L") || style.includes("BL"))
fontFamily = "Manrope_300Light";
else if (style.includes("R")) fontFamily = "Manrope_400Regular";
else if (style.includes("M")) fontFamily = "Manrope_500Medium";
else if (style.includes("BO") || style.includes("H"))
fontFamily = "Manrope_700Bold";
else {
const baseStyle = style.slice(0, 6) as TextStyleBase;
switch (baseStyle) {
case "text10":
case "text20":
fontFamily = "Manrope_700Bold";
break;
case "text30":
case "text40":
fontFamily = "Manrope_600SemiBold";
break;
case "text50":
fontFamily = "Manrope_400Regular";
break;
default:
fontFamily = "Manrope_300Light";
return {
style: [
Typography.text50,
textStyle ? typographies[textStyle] : undefined,
],
};
}
);
}
}, [loaded]);
switch (style.slice(0, 6) as TextStyleBase) {
case "text10":
fontSize = 64;
break;
case "text20":
fontSize = 50;
break;
case "text30":
fontSize = 36;
break;
case "text40":
fontSize = 28;
break;
case "text50":
fontSize = 24;
break;
case "text60":
fontSize = 20;
break;
case "text70":
fontSize = 16;
break;
case "text80":
fontSize = 14;
break;
case "text90":
fontSize = 12;
break;
case "text100":
fontSize = 10;
break;
default:
fontSize = 16;
}
if (!loaded) {
return null;
}
return {fontFamily, fontSize};
};
export default function RootLayout() {
const [loaded] = useFonts({
Manrope_200ExtraLight,
Manrope_300Light,
Manrope_400Regular,
Manrope_500Medium,
Manrope_600SemiBold,
Manrope_700Bold,
Manrope_800ExtraBold,
PlusJakartaSans_200ExtraLight,
PlusJakartaSans_300Light,
PlusJakartaSans_400Regular,
PlusJakartaSans_500Medium,
PlusJakartaSans_600SemiBold,
PlusJakartaSans_700Bold,
PlusJakartaSans_800ExtraBold,
PlusJakartaSans_200ExtraLight_Italic,
PlusJakartaSans_300Light_Italic,
PlusJakartaSans_400Regular_Italic,
PlusJakartaSans_500Medium_Italic,
PlusJakartaSans_600SemiBold_Italic,
PlusJakartaSans_700Bold_Italic,
PlusJakartaSans_800ExtraBold_Italic,
Poppins_100Thin,
Poppins_100Thin_Italic,
Poppins_200ExtraLight,
Poppins_200ExtraLight_Italic,
Poppins_300Light,
Poppins_300Light_Italic,
Poppins_400Regular,
Poppins_400Regular_Italic,
Poppins_500Medium,
Poppins_500Medium_Italic,
Poppins_600SemiBold,
Poppins_600SemiBold_Italic,
Poppins_700Bold,
Poppins_700Bold_Italic,
Poppins_800ExtraBold,
Poppins_800ExtraBold_Italic,
Poppins_900Black,
Poppins_900Black_Italic,
});
useEffect(() => {
if (loaded) {
const typographies: Partial<Record<TextStyle, FontStyle>> = {};
(
[
"text10",
"text20",
"text30",
"text40",
"text50",
"text60",
"text70",
"text80",
"text90",
"text100",
] as const
).forEach((baseStyle) => {
typographies[baseStyle] = getManropeFontStyle(baseStyle);
(["R", "M", "BO", "H", "BL", "L"] as const).forEach((modifier) => {
const style = `${baseStyle}${modifier}` as TextStyle;
typographies[style] = getManropeFontStyle(style);
});
});
Typography.loadTypographies(typographies);
ThemeManager.setComponentTheme(
"Text",
(props: ExtendedTextProps) => {
const textStyle = (
Object.keys(props) as Array<keyof ExtendedTextProps>
).find((key) => typographies[key as TextStyle]) as
| TextStyle
| undefined;
return {
style: [
Typography.text50,
textStyle ? typographies[textStyle] : undefined,
],
};
}
);
}
}, [loaded]);
if (!loaded) {
return null;
}
return (
<PersistQueryClientProvider>
<AuthContextProvider>
<ThemeProvider value={DefaultTheme}>
<Stack>
<Stack.Screen name="(auth)" options={{headerShown: false}}/>
<Stack.Screen name="(unauth)" options={{headerShown: false}}/>
<Stack.Screen name="+not-found"/>
</Stack>
<Toast/>
</ThemeProvider>
</AuthContextProvider>
</PersistQueryClientProvider>
);
return (
<QueryClientProvider client={queryClient}>
<AuthContextProvider>
<ThemeProvider value={DefaultTheme}>
<Stack>
<Stack.Screen name="(auth)" options={{ headerShown: false }} />
<Stack.Screen name="(unauth)" options={{ headerShown: false }} />
<Stack.Screen name="+not-found" />
</Stack>
<Toast />
</ThemeProvider>
</AuthContextProvider>
</QueryClientProvider>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -1,19 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const ArrowRightIcon = (props: SvgProps) => (
<Svg
width={9}
height={15}
viewBox="0 0 9 15"
fill="none"
{...props}
>
<Path
stroke="#ACACAC"
strokeLinecap="round"
strokeWidth={2}
d="M1.272 1.803 7.16 7.69a.16.16 0 0 1 0 .226l-5.887 5.887"
/>
</Svg>
)
export default ArrowRightIcon

View File

@ -4,7 +4,6 @@ const CalendarIcon: React.FC<SvgProps> = (props) => (
<Svg
width={props.width || 21}
height={props.height || 21}
viewBox="0 0 21 21"
fill="none"
{...props}
>

View File

@ -1,20 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const CheckmarkIcon = (props: SvgProps) => (
<Svg
width={13}
height={10}
viewBox="0 0 13 10"
fill={props.color || "white"}
{...props}
>
<Path
stroke="#fff"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.95}
d="m1.48 5.489 3.2 3.178 7.2-7.15"
/>
</Svg>
)
export default CheckmarkIcon

View File

@ -1,22 +0,0 @@
import * as React from "react";
import Svg, { SvgProps, Path } from "react-native-svg";
const CircledXIcon = (props: SvgProps) => (
<Svg
width={props.width || 22}
height={props.height || 21}
viewBox="0 0 22 21"
fill="none"
{...props}
>
<Path
stroke={props.color || "#BBB"}
d="M11 20.5c5.523 0 10-4.477 10-10S16.523.5 11 .5 1 4.977 1 10.5s4.477 10 10 10Z"
/>
<Path
stroke={props.color || "#BBB"}
strokeLinecap="round"
d="m13.75 7.75-5.5 5.5m0-5.5 5.5 5.5"
/>
</Svg>
);
export default CircledXIcon;

View File

@ -1,20 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const ClockOIcon = (props: SvgProps) => (
<Svg
width={props.height || 22}
height={props.height || 22}
viewBox="0 0 22 22"
fill="none"
{...props}
>
<Path
stroke={props.color || "#919191"}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11 5.444V11l1.667 2.778M21 11c0 5.523-4.477 10-10 10S1 16.523 1 11 5.477 1 11 1s10 4.477 10 10Z"
/>
</Svg>
)
export default ClockOIcon

View File

@ -5,14 +5,13 @@ const CloseXIcon: React.FC<SvgProps> = (props) => (
width={15}
height={15}
fill="none"
viewBox="0 0 15 15"
{...props}
>
<Path
stroke="#AAA"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={props.strokeWidth || 1.394}
strokeWidth={1.394}
d="m1.573 1.543 12.544 12.544M1.573 14.087 14.117 1.543"
/>
</Svg>

View File

@ -1,19 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const DrawerIcon = (props: SvgProps) => (
<Svg
width={27}
height={18}
fill="none"
{...props}
>
<Path
stroke="#83807F"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2.7}
d="M2 1.995h22.667M2 9.14h14.167M2 16.285h7.083"
/>
</Svg>
)
export default DrawerIcon

View File

@ -1,20 +0,0 @@
import * as React from "react";
import Svg, { SvgProps, Path } from "react-native-svg";
const DropdownIcon = (props: SvgProps) => (
<Svg
width={props.width || 15}
height={props.height || 11}
fill="none"
viewBox="0 0 15 11"
{...props}
>
<Path
stroke={props.color || "#FD1775"}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={props.strokeWidth || 1.393}
d="M4.713 1.318h9.056m-9.056 4.18h9.056m-9.056 4.18h9.056M1.23 1.667h.697V.97H1.23v.696Zm0 4.18h.697V5.15H1.23v.696Zm0 4.18h.697V9.33H1.23v.696Z"
/>
</Svg>
);
export default DropdownIcon;

View File

@ -1,17 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const EmailIcon = (props: SvgProps) => (
<Svg
width={props.width || 20}
height={props.height || 16}
viewBox="0 0 20 16"
fill="none"
{...props}
>
<Path
fill={props.color || "#fff"}
d="M19.948 2.385a2.767 2.767 0 0 0-.76-1.422A2.768 2.768 0 0 0 17.225.15H2.774A2.772 2.772 0 0 0 0 2.925v10.15c0 .389.083.763.23 1.101a2.719 2.719 0 0 0 .774 1.035c.48.398 1.1.638 1.77.638h14.452a2.755 2.755 0 0 0 1.961-.813c.245-.245.447-.537.586-.86v-.002c.147-.338.227-.71.227-1.1V2.925c0-.182-.018-.363-.052-.539ZM1.817 1.967a1.34 1.34 0 0 1 .957-.397h14.452a1.335 1.335 0 0 1 1.079.54l-7.575 6.6a1.11 1.11 0 0 1-1.46 0L1.698 2.107c.034-.048.075-.095.119-.139Zm-.398 11.107V3.575l5.482 4.782-5.479 4.777c-.003-.018-.003-.039-.003-.06Zm15.807 1.355H2.774c-.245 0-.475-.064-.67-.178l5.78-5.037.54.47a2.406 2.406 0 0 0 3.155 0l.54-.47 5.778 5.037a1.338 1.338 0 0 1-.671.178Zm1.355-1.354c0 .02 0 .04-.003.059L13.1 8.36l5.48-4.782v9.497Z"
/>
</Svg>
)
export default EmailIcon

View File

@ -1,20 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const FeedbackNavIcon = (props: SvgProps) => (
<Svg
width={25}
height={25}
fill="none"
viewBox="0 0 24 24"
{...props}
>
<Path
stroke="#ea156d"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M10.5 21H4a7.001 7.001 0 0 1 6-6.93m6.498 2.142c-.7-.78-1.867-.989-2.744-.275-.877.713-1 1.906-.311 2.75.388.476 1.312 1.311 2.042 1.948.347.302.52.453.73.515.178.053.387.053.566 0 .21-.061.382-.213.729-.515.73-.637 1.654-1.472 2.043-1.948.688-.844.58-2.044-.312-2.75-.892-.706-2.044-.504-2.743.275ZM15 7a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"
/>
</Svg>
)
export default FeedbackNavIcon

View File

@ -1,17 +0,0 @@
import * as React from "react";
import Svg, { SvgProps, Path } from "react-native-svg";
const MenuDotsIcon = (props: SvgProps) => (
<Svg
width={props.width || 4}
height={props.height || 15}
viewBox="0 0 4 15"
fill="none"
{...props}
>
<Path
fill={props.color || "#7C7C7C"}
d="M.88 7.563a1.56 1.56 0 1 0 3.12 0 1.56 1.56 0 0 0-3.12 0Zm0-5.2A1.56 1.56 0 1 0 4 2.426a1.56 1.56 0 0 0-3.12-.063Zm0 10.4A1.56 1.56 0 1 0 4 12.701a1.56 1.56 0 0 0-3.12.062Z"
/>
</Svg>
);
export default MenuDotsIcon;

View File

@ -7,8 +7,8 @@ interface MenuIconProps extends SvgProps {
const MenuIcon: React.FC<MenuIconProps> = (props) => (
<Svg
width={props.width || 24}
height={props.height || 16}
width={24}
height={16}
viewBox="0 0 24 16"
fill="none"
{...props}

View File

@ -1,15 +1,14 @@
import * as React from "react";
import Svg, { Path, SvgProps } from "react-native-svg";
import * as React from "react"
import Svg, { Path, SvgProps } from "react-native-svg"
const NavBrainDumpIcon: React.FC<SvgProps> = (props) => (
<Svg
width={props.width || 22}
height={props.height || 28}
viewBox="0 0 22 28"
width={22}
height={28}
fill="none"
{...props}
>
<Path
stroke={props.color || "#F90"}
stroke="#F90"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit={10}
@ -17,7 +16,7 @@ const NavBrainDumpIcon: React.FC<SvgProps> = (props) => (
d="M21.1.859H3.994C2.284.859.976 2.167.976 3.877c0 1.71 1.308 3.019 3.018 3.019H21.1V27.02"
/>
<Path
stroke={props.color || "#F90"}
stroke="#F90"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit={10}
@ -25,7 +24,7 @@ const NavBrainDumpIcon: React.FC<SvgProps> = (props) => (
d="M21.1 27.021H3.994c-1.71 0-3.018-1.308-3.018-3.018V3.878M21.097 3.878H3.991"
/>
<Path
stroke={props.color || "#F90"}
stroke="#F90"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit={10}
@ -33,5 +32,5 @@ const NavBrainDumpIcon: React.FC<SvgProps> = (props) => (
d="M6.007 6.897v12.075l3.019-1.006 3.018 1.006V6.897"
/>
</Svg>
);
export default NavBrainDumpIcon;
)
export default NavBrainDumpIcon

View File

@ -1,9 +1,9 @@
import * as React from "react";
import Svg, { Path, SvgProps } from "react-native-svg";
import * as React from "react"
import Svg, { Path, SvgProps } from "react-native-svg"
const NavCalendarIcon: React.FC<SvgProps> = (props) => (
<Svg
width={props.width || 28}
height={props.height || 28}
width={28}
height={28}
viewBox="0 0 28 28"
fill="none"
{...props}
@ -16,5 +16,5 @@ const NavCalendarIcon: React.FC<SvgProps> = (props) => (
d="M1.825 10.075h25.043m-5.565 5.567L7.39 15.64m4.638 5.566H7.39m0-19.478V4.51m13.913-2.782V4.51M6.277 26.77h16.139c1.558 0 2.337 0 2.933-.303.523-.267.949-.692 1.216-1.216.303-.595.303-1.375.303-2.933V8.962c0-1.558 0-2.337-.303-2.933a2.782 2.782 0 0 0-1.216-1.216c-.596-.303-1.375-.303-2.933-.303H6.277c-1.558 0-2.337 0-2.933.303-.523.267-.949.693-1.216 1.216-.303.596-.303 1.375-.303 2.933v13.356c0 1.558 0 2.338.303 2.933.267.523.693.95 1.216 1.216.596.303 1.375.303 2.933.303Z"
/>
</Svg>
);
export default NavCalendarIcon;
)
export default NavCalendarIcon

View File

@ -2,18 +2,17 @@ import * as React from "react";
import Svg, { Path, SvgProps } from "react-native-svg";
const NavGroceryIcon: React.FC<SvgProps> = (props) => (
<Svg
width={props.width || 29}
height={props.width || 32}
viewBox="0 0 29 32"
width={29}
height={32}
fill="none"
{...props}
>
<Path
fill={props.color || "#50BE0C"}
fill="#50BE0C"
d="M27.8 12c-.888-2.27-2.662-4.14-4.983-4.956-2.518-.883-5.143-.382-7.636.307-.047-1.362.068-2.728.262-4.076.11-.761.634-2.335-.668-2.389-1.081-.045-1.084 1.402-1.19 2.14-.203 1.416-.323 2.85-.284 4.281-.599-.1-1.19-.322-1.787-.446a13.485 13.485 0 0 0-2.704-.3c-1.752 0-3.48.465-4.922 1.479C1.09 10.01 0 13.446.046 16.747c.052 3.575 1.263 6.99 3.3 9.905.899 1.288 1.932 2.522 3.21 3.451 1.241.903 2.628 1.325 4.133 1.54.64.093 1.29.096 1.927-.009.557-.09 1.078-.325 1.63-.419.417-.07 1.005.258 1.408.348a6.297 6.297 0 0 0 2.096.107c2.563-.292 4.594-1.449 6.28-3.387 3.71-4.264 5.921-10.791 3.77-16.284Zm-1.69 8.743c-.474 1.663-1.225 3.182-2.195 4.608-.86 1.263-1.855 2.514-3.131 3.377-1.172.79-2.76 1.223-4.173 1.093-.719-.065-1.373-.41-2.087-.478-.8-.076-1.538.352-2.318.459-3.064.416-5.485-1.665-7.146-3.972-2.04-2.831-3.249-6.214-3.134-9.732.106-3.223 1.643-6.55 4.998-7.432 1.678-.44 3.446-.188 5.099.238.715.183 1.454.48 2.196.52.572.066 1.2-.196 1.74-.344 3.233-.89 6.873-1.105 9.124 1.855 2.08 2.732 1.925 6.666 1.027 9.808Z"
/>
<Path
fill={props.color || "#50BE0C"}
fill="#50BE0C"
d="M12 17.966c-.778.285-1.977.71-2.432 1.454.11-.183.221-.363-.002.002-.222.365-.113.186-.001.003-.668 1.099.272 2.53 1.547 2.347 1.258-.18 1.378-1.419 1.364-2.443a8.822 8.822 0 0 0-.095-1.282c-.043-.264-.157-.164-.382-.08ZM18.096 18.917c-.435-.304-.919-.542-1.405-.752-.118-.05-.698-.375-.832-.297.018-.01.036-.021 0 0-.036.023-.02.012-.001.001-.11.07-.096.609-.104.716a9.003 9.003 0 0 0-.01 1.534c.1 1.117 1.049 2.082 2.228 1.517 1.165-.558 1.095-2.04.124-2.719ZM12.223 3.815C12.343.28 8.347-.271 6.922.432c.371 4.075 3.48 4.164 5.301 3.383Z"
/>
</Svg>

View File

@ -3,7 +3,7 @@ import Svg, { Path, SvgProps } from "react-native-svg"
const NavToDosIcon: React.FC<SvgProps> = (props) => (
<Svg
width={props.width || 30}
height={props.height || 30}
height={props.width || 30}
viewBox="0 0 30 30"
fill="none"
{...props}

View File

@ -3,8 +3,8 @@ import Svg, { Path, LinearGradient, Stop, SvgProps } from "react-native-svg";
const OutlookIcon: React.FC<SvgProps> = (props) => (
<Svg
width={props.width || 34}
height={props.height || 34}
width={34}
height={34}
viewBox="0 0 48 48"
{...props}
>

View File

@ -1,20 +0,0 @@
import * as React from "react";
import Svg, { SvgProps, Path } from "react-native-svg";
const PlusIcon = (props: SvgProps) => (
<Svg
width={props.width || 14}
height={props.height || 15}
viewBox="0 0 14 15"
fill="none"
{...props}
>
<Path
stroke="#fff"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M1 7.632h12m-6-6v12"
/>
</Svg>
);
export default PlusIcon;

View File

@ -1,20 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const QRIcon = (props: SvgProps) => (
<Svg
width={props.width || 19}
height={props.height || 20}
viewBox="0 0 19 20"
fill="none"
{...props}
>
<Path
stroke={props.color || "#fff"}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.764}
d="M5.086 10.441h4.41v4.41m-7.93-4.41h-.008m4.418 4.41h-.008m3.536 3.528h-.008m7.946-7.938h-.008m-15.876 4.41H2.88m9.702-4.41h1.764M1.557 18.38h4.41M9.497 1.621v5.292m4.939 11.466h1.587c.494 0 .741 0 .93-.096.166-.085.3-.22.385-.386.097-.188.097-.435.097-.93V15.38c0-.494 0-.74-.097-.93a.882.882 0 0 0-.385-.385c-.189-.096-.436-.096-.93-.096h-1.587c-.494 0-.741 0-.93.096a.881.881 0 0 0-.385.386c-.096.188-.096.435-.096.93v1.587c0 .494 0 .74.096.93.084.166.22.3.385.385.189.096.436.096.93.096Zm0-11.466h1.587c.494 0 .741 0 .93-.096.166-.085.3-.22.385-.385.097-.19.097-.436.097-.93V3.914c0-.494 0-.74-.097-.93a.882.882 0 0 0-.385-.385c-.189-.096-.436-.096-.93-.096h-1.587c-.494 0-.741 0-.93.096a.881.881 0 0 0-.385.386c-.096.188-.096.435-.096.93v1.587c0 .494 0 .74.096.93.084.165.22.3.385.385.189.096.436.096.93.096Zm-11.466 0h1.587c.494 0 .741 0 .93-.096.166-.085.3-.22.385-.385.097-.19.097-.436.097-.93V3.914c0-.494 0-.74-.097-.93a.882.882 0 0 0-.385-.385c-.189-.096-.436-.096-.93-.096H2.97c-.494 0-.741 0-.93.096a.882.882 0 0 0-.385.386c-.096.188-.096.435-.096.93v1.587c0 .494 0 .74.096.93.084.165.22.3.385.385.189.096.436.096.93.096Z"
/>
</Svg>
)
export default QRIcon

View File

@ -1,18 +0,0 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const RepeatIcon = (props: SvgProps) => (
<Svg
width={props.height || 13}
height={props.height || 13}
fill="none"
{...props}
>
<Path
stroke={props.color || "#858585"}
strokeLinecap="round"
strokeLinejoin="round"
d="M1.158 7.197a5.42 5.42 0 0 1 9.58-4.103m0 0V1.099m0 1.995v.037H8.705m3.21 2.71a5.42 5.42 0 0 1-9.444 4.263m0 .001v-.198h2.033m-2.033.198v1.835"
/>
</Svg>
)
export default RepeatIcon

Some files were not shown because too many files have changed in this diff Show More