Compare commits

...

5 Commits

132 changed files with 13132 additions and 5079 deletions

7
.gitignore vendored
View File

@ -58,3 +58,10 @@ buck-out/
# CocoaPods
/ios/Pods/
.vscode
.bundle
android/.settings
android/app/.settings
android/*.hprof

46
App.js
View File

@ -7,21 +7,22 @@
*/
import React, { Component } from 'react'
import { Platform, StyleSheet, Text, StatusBar, TouchableOpacity, View } from 'react-native'
import { StatusBar, StyleSheet, Text, TouchableOpacity } from 'react-native'
import MainNav from './src/navigation/MainNav'
import firebase, { Notification } from 'react-native-firebase'
import { store, persistor } from './src/redux/store'
import messaging from "@react-native-firebase/messaging"
import { persistor, store } from './src/redux/store'
import { Provider } from 'react-redux'
import { registerDevice, testConnect ,news} from './src/api/UserApi'
import { appSetPushToken, appSetDevice, appCleanDevice,appSetNotification } from './src/redux/app/action'
import { setLanguage, setStore as setApiStore, setToken } from 'src/api/api'
import { registerDevice } from './src/api/UserApi'
import { appSetDevice, appSetPushToken } from './src/redux/app/action'
import { setLanguage, setToken } from 'src/api/api'
import { PersistGate } from 'redux-persist/integration/react'
import { create } from 'apisauce'
import Toast from 'react-native-toast-message'
import SplashScreen from 'react-native-splash-screen'
import { setBaseUrlByServerMode } from './src/api/api'
Text.defaultProps = Text.defaultProps || {};
Text.defaultProps.allowFontScaling = false;
Text.defaultProps = Text.defaultProps || {}
Text.defaultProps.allowFontScaling = false
if (TouchableOpacity.defaultProps == null) TouchableOpacity.defaultProps = {}
TouchableOpacity.defaultProps.activeOpacity = 0.7
@ -29,7 +30,7 @@ TouchableOpacity.defaultProps.activeOpacity = 0.7
// setApiStore(store)
class App extends Component {
constructor(props) {
constructor (props) {
super(props)
this._setDataFromInitState = this._setDataFromInitState.bind(this)
}
@ -37,15 +38,15 @@ class App extends Component {
componentDidMount = () => {
SplashScreen.hide()
};
}
initNotification = async () => {
await this.setPermission()
const fcmToken = await firebase.messaging().getToken()
const fcmToken = await messaging().getAPNSToken();
if (fcmToken) {
store.dispatch(appSetPushToken(fcmToken))
const resultSendDevice = await registerDevice(fcmToken)
console.log(' re sult register_device =>',resultSendDevice);
console.log(' re sult register_device =>', resultSendDevice)
if (resultSendDevice.ok && resultSendDevice.data.success) {
store.dispatch(appSetDevice(resultSendDevice.data.device))
}
@ -55,23 +56,27 @@ class App extends Component {
setPermission = async () => {
try {
const enabled = await firebase.messaging().hasPermission()
await messaging().registerDeviceForRemoteMessages();
const authStatus = await messaging().requestPermission();
const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED || authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (!enabled) {
await firebase.messaging().requestPermission()
await messaging().requestPermission()
}
} catch (error) {
console.log('error', error)
}
}
_setDataFromInitState() {
_setDataFromInitState () {
const appState = store.getState().app
let device = appState.device;
let device = appState.device
setBaseUrlByServerMode(appState.server_mode)
if (appState.token) {
setToken(appState.token)
}
if(appState.lang){
if (appState.lang) {
setLanguage(appState.lang)
}
@ -83,14 +88,15 @@ class App extends Component {
}
render() {
render () {
return (
<Provider store={store}>
<PersistGate persistor={persistor} loading={null} onBeforeLift={this._setDataFromInitState}>
<StatusBar barStyle="light-content"/>
<MainNav />
<MainNav/>
</PersistGate>
<Toast />
</Provider>
)
}

View File

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>csareactrn60</name>
<name>charoensin</name>
<comment>Project android created by Buildship.</comment>
<projects>
</projects>
@ -14,4 +14,15 @@
<natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>0</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@ -1,2 +0,0 @@
connection.project.dir=
eclipse.preferences.version=1

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View File

@ -20,4 +20,15 @@
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>1673516293498</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@ -1,2 +0,0 @@
connection.project.dir=..
eclipse.preferences.version=1

View File

@ -131,9 +131,11 @@ android {
applicationId "th.co.csasset.mobile"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 60
versionName "2.12"
versionCode 84
versionName "2.33"
vectorDrawables.useSupportLibrary = true
missingDimensionStrategy 'react-native-camera', 'general'
multiDexEnabled true
}
splits {
abi {
@ -208,7 +210,10 @@ android {
}
}
// def multidex_version = "2.0.1"
dependencies {
implementation project(':react-native-permissions')
implementation project(':react-native-camera')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+" // From node_modules
if (enableHermes) {
@ -223,6 +228,7 @@ dependencies {
implementation "com.google.firebase:firebase-core:16.0.9"
implementation "com.google.firebase:firebase-config:17.0.0"
implementation "com.google.firebase:firebase-messaging:18.0.0"
// implementation "androidx.multidex:multidex:$multidex_version"
// implementation 'com.facebook.android:facebook-android-sdk:[5,6)'
}

View File

@ -0,0 +1,42 @@
{
"project_info": {
"project_number": "300814322402",
"firebase_url": "https://charoensin-ec628.firebaseio.com",
"project_id": "charoensin-ec628",
"storage_bucket": "charoensin-ec628.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:300814322402:android:61e2ca18a6ba4174",
"android_client_info": {
"package_name": "th.co.csasset.mobile"
}
},
"oauth_client": [
{
"client_id": "300814322402-82gqcb4dte5m2tv1dr2imsf0u7regk87.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAIXzIwPy-023B3sbDQv42LaxXaSnJcWmU"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"
}

View File

@ -1,39 +1,45 @@
{
"project_info": {
"project_number": "300814322402",
"firebase_url": "https://charoensin-ec628.firebaseio.com",
"project_id": "charoensin-ec628",
"storage_bucket": "charoensin-ec628.appspot.com"
"project_number": "468878476620",
"firebase_url": "https://csasset-mobile.firebaseio.com",
"project_id": "csasset-mobile",
"storage_bucket": "csasset-mobile.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:300814322402:android:61e2ca18a6ba4174",
"mobilesdk_app_id": "1:468878476620:android:61e2ca18a6ba4174",
"android_client_info": {
"package_name": "th.co.csasset.mobile"
}
},
"oauth_client": [
{
"client_id": "300814322402-82gqcb4dte5m2tv1dr2imsf0u7regk87.apps.googleusercontent.com",
"client_id": "468878476620-v3rqr1b2bta862r6q974csuc3rq917ni.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAIXzIwPy-023B3sbDQv42LaxXaSnJcWmU"
"current_key": "AIzaSyB7o8KiFwABvfyYubdWTcjpm3Y6ciCrO1I"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
"other_platform_oauth_client": [
{
"client_id": "468878476620-v3rqr1b2bta862r6q974csuc3rq917ni.apps.googleusercontent.com",
"client_type": 3
},
"ads_service": {
"status": 2
{
"client_id": "468878476620-dn0mrhcve5jjpfst3u1vlm4k00uackb6.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "th.co.csasset.mobile",
"app_store_id": "1455804320"
}
}
]
}
}
}

Binary file not shown.

View File

@ -0,0 +1,18 @@
{
"version": 2,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "th.co.csasset.mobile",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"versionCode": 84,
"versionName": "2.33",
"outputFile": "app-release.apk"
}
]
}

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.csareactrn60;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceEventListener;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
/**
* Class responsible of loading Flipper inside your React Native application. This is the debug
* flavor of it. Here you can add your own plugins and customize the Flipper setup.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}

View File

@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="th.co.csasset.mobile">
<uses-permission android:name="android.permission.INTERNET"/>
@ -16,25 +17,32 @@
android:icon="@mipmap/ic_launcher"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:hardwareAccelerated="false"
android:hardwareAccelerated="true"
android:largeHeap="true">
<!-- android:usesCleartextTraffic="true" -->
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action
android:name="android.intent.action.MAIN"
android:exported="true"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
<service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService">
<service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService"
android:exported="true"
tools:ignore="MissingClass">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService">
<service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>

View File

@ -9,15 +9,17 @@ import com.facebook.react.bridge.JavaScriptExecutorFactory;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
//import com.facebook.reactnative.androidsdk.BuildConfig;
import com.facebook.soloader.SoLoader;
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.reactnativecommunity.cameraroll.CameraRollPackage;
import org.reactnative.camera.RNCameraPackage;
// Firebase
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage;
//import io.invertase.firebase.messaging.ReactNativeFirebaseMessagingPackage;
//import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
//import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage;
import com.facebook.reactnative.androidsdk.FBSDKPackage;
@ -37,9 +39,10 @@ public class MainApplication extends Application implements ReactApplication {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new RNFirebaseNotificationsPackage());
packages.add(new RNFirebaseMessagingPackage());
packages.add(new RNFirebaseRemoteConfigPackage());
// packages.add(new RNFirebaseNotificationsPackage());
// packages.add(new ReactNativeFirebaseMessagingPackage());
// packages.add(new RNFirebaseRemoteConfigPackage());
// packages.add(new RNCameraPackage());
return packages;
}

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
android:insetTop="@dimen/abc_edit_text_inset_top_material"
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">
<selector>
<!--
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
-->
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
</selector>
</inset>

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.csareactrn60;
import android.content.Context;
import com.facebook.react.ReactInstanceManager;
/**
* Class responsible of loading Flipper inside your React Native application. This is the release
* flavor of it so it's empty as we don't want to load Flipper.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
// Do nothing as we don't want to initialize Flipper on Release.
}
}

View File

@ -4,26 +4,30 @@ buildscript {
ext {
googlePlayServiceVersion = "17.0.0"
buildToolsVersion = "28.0.3"
kotlinVersion = "1.5.20"
minSdkVersion = 21
compileSdkVersion = 28
targetSdkVersion = 28
compileSdkVersion = 31
targetSdkVersion = 31
}
repositories {
google()
mavenCentral()
jcenter()
// jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:3.4.1")
classpath 'com.google.gms:google-services:4.2.0'
classpath('com.android.tools.build:gradle:4.2.2')
classpath('com.google.gms:google-services:4.3.14')
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
def REACT_NATIVE_VERSION = new File(['node', '--print',"JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim())
allprojects {
repositories {
mavenCentral()
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
@ -35,9 +39,14 @@ allprojects {
}
google()
jcenter()
// jcenter()
maven { url 'https://maven.google.com' }
maven { url "https://jitpack.io" }
}
configurations.all {
resolutionStrategy {
force "com.facebook.react:react-native:" + REACT_NATIVE_VERSION
}
}
}

View File

@ -1,26 +1,20 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
## For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# Default value: -Xmx1024m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useAndroidX=true
android.enableJetifier=true
#Fri Apr 07 15:17:20 ICT 2023
MYAPP_RELEASE_STORE_FILE=charoensin.release.keystore
MYAPP_RELEASE_KEY_ALIAS=charoensin
MYAPP_RELEASE_STORE_PASSWORD=aabbccddee
MYAPP_RELEASE_KEY_PASSWORD=aabbccddee
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
android.useAndroidX=true
android.enableJetifier=true
MYAPP_RELEASE_STORE_PASSWORD=aabbccddee

Binary file not shown.

View File

@ -1,5 +1,7 @@
#Fri Jan 13 09:46:32 ICT 2023
networkTimeout=10000
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

288
android/gradlew vendored
View File

@ -1,13 +1,13 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@ -17,78 +17,113 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# 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/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@ -105,84 +140,105 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

40
android/gradlew.bat vendored
View File

@ -5,7 +5,7 @@
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,10 +25,14 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -51,7 +55,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -61,38 +65,26 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@ -1,4 +1,20 @@
rootProject.name = 'charoensin'
include ':@react-native-firebase_config'
project(':@react-native-firebase_config').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-firebase/config/android')
include ':@react-native-firebase_config'
project(':@react-native-firebase_config').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-firebase/config/android')
include ':@react-native-firebase_config'
project(':@react-native-firebase_config').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-firebase/config/android')
include ':@react-native-firebase_config'
project(':@react-native-firebase_config').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-firebase/config/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
include ':react-native-permissions'
project(':react-native-permissions').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-permissions/android')
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-fbsdk'

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

BIN
assets/images/logo_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
assets/images/star_grey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

View File

@ -1,3 +1,9 @@
export default {
API_BASE_URL: 'https://app.csasset.co.th/mobile',
API_BASE_URL_PROD: 'https://app.csasset.co.th/mobile',
// API_BASE_URL_POWER_CONDO_DEV: 'https://power-condo.testsiteth.xyz',
API_BASE_URL_POWER_CONDO_DEV: 'http://54.255.251.43',
API_BASE_URL_POWER_CONDO_PROD: 'https://powercondo.csasset.co.th',
WEB_BASE_URL_PROD: 'https://app.csasset.co.th',
API_BASE_URL_DEV: 'https://csa-test.bda.co.th/mobile',
WEB_BASE_URL_DEV: 'https://csa-test.bda.co.th'
}

11
firebase.json Normal file
View File

@ -0,0 +1,11 @@
{
"react-native": {
"messaging_ios_auto_register_for_remote_messages": false,
"crashlytics_auto_collection_enabled": false,
"messaging_android_notification_channel_id": "high-priority",
"crashlytics_debug_enabled": true,
"crashlytics_ndk_enabled": false,
"crashlytics_is_error_generation_on_js_crash_enabled": false,
"crashlytics_javascript_exception_handler_chaining_enabled": false
}
}

3
ios/Gemfile Normal file
View File

@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "fastlane"

View File

@ -1,6 +1,8 @@
platform :ios, '9.0'
platform :ios, '13.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
xcodeproj 'csareactrn60'
target 'csareactrn60' do
# Pods for csareactrn60
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
@ -26,7 +28,7 @@ target 'csareactrn60' do
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
pod 'React-callinvoker', :path => "../node_modules/react-native/ReactCommon/callinvoker"
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
@ -37,15 +39,47 @@ target 'csareactrn60' do
pod 'react-native-fbsdk', :path => '../node_modules/react-native-fbsdk'
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-AppTrackingTransparency', :path => "#{permissions_path}/AppTrackingTransparency"
pod 'Permission-BluetoothPeripheral', :path => "#{permissions_path}/BluetoothPeripheral"
pod 'Permission-Calendars', :path => "#{permissions_path}/Calendars"
pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
pod 'Permission-Contacts', :path => "#{permissions_path}/Contacts"
pod 'Permission-FaceID', :path => "#{permissions_path}/FaceID"
pod 'Permission-LocationAccuracy', :path => "#{permissions_path}/LocationAccuracy"
pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways"
pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse"
pod 'Permission-MediaLibrary', :path => "#{permissions_path}/MediaLibrary"
pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone"
pod 'Permission-Motion', :path => "#{permissions_path}/Motion"
pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications"
pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary"
pod 'Permission-PhotoLibraryAddOnly', :path => "#{permissions_path}/PhotoLibraryAddOnly"
pod 'Permission-Reminders', :path => "#{permissions_path}/Reminders"
pod 'Permission-Siri', :path => "#{permissions_path}/Siri"
pod 'Permission-SpeechRecognition', :path => "#{permissions_path}/SpeechRecognition"
pod 'Permission-StoreKit', :path => "#{permissions_path}/StoreKit"
pod 'FBSDKCoreKit'
pod 'FBSDKLoginKit'
pod 'FBSDKShareKit'
#Firebase
pod 'Firebase/Messaging', '~> 6.8.0'
pod 'react-native-view-shot', :path => '../node_modules/react-native-view-shot'
pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker'
use_native_modules!
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
pod 'react-native-camera', :path => '../node_modules/react-native-camera'
pod 'RNPermissions', :path => '../node_modules/react-native-permissions'
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
pod 'Firebase', :modular_headers => true
pod 'FirebaseCoreInternal', :modular_headers => true
pod 'FirebaseCore', :modular_headers => true
pod 'GoogleUtilities', :modular_headers => true
end

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
LastUpgradeVersion = "1120"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"
@ -55,6 +55,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "csareactrn60-tvOS.app"
BlueprintName = "csareactrn60-tvOS"
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@ -67,17 +76,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "csareactrn60-tvOS.app"
BlueprintName = "csareactrn60-tvOS"
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -99,8 +97,6 @@
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
LastUpgradeVersion = "1120"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"
@ -55,6 +55,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "csareactrn60.app"
BlueprintName = "csareactrn60"
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@ -67,17 +76,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "csareactrn60.app"
BlueprintName = "csareactrn60"
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -99,8 +97,6 @@
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -69,6 +69,20 @@
<string>Choose a picture for user profile image or save image.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to choose photos to upload profile picture and create support ticket.</string>
<key>NSContactsUsageDescription</key>
<string>no use</string>
<key>NSCalendarsUsageDescription</key>
<string>no use</string>
<key>NSAppleMusicUsageDescription</key>
<string>no use</string>
<key>NSMotionUsageDescription</key>
<string>no use</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>no use</string>
<key>NSSiriUsageDescription</key>
<string>no use</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>no use</string>
<key>UIAppFonts</key>
<array>
<string>arial.ttf</string>

View File

@ -4,5 +4,9 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>

8
ios/fastlane/Appfile Normal file
View File

@ -0,0 +1,8 @@
app_identifier("th.co.csasset.mobile") # The bundle identifier of your app
apple_id("btanawut@gmail.com") # Your Apple email address
itc_team_id("120264177") # App Store Connect Team ID
team_id("84F3R56BUC") # Developer Portal Team ID
# For more information about the Appfile, see:
# https://docs.fastlane.tools/advanced/#appfile

27
ios/fastlane/Fastfile Normal file
View File

@ -0,0 +1,27 @@
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:ios)
platform :ios do
desc "Push a new beta build to TestFlight"
lane :beta do
increment_build_number(xcodeproj: "csareactrn60.xcodeproj")
build_app(workspace: "csareactrn60.xcworkspace", scheme: "csareactrn60")
upload_to_testflight(
skip_waiting_for_build_processing:true
)
end
end

View File

@ -9,7 +9,9 @@
"postinstall": "sh ./fix.sh",
"prod-android": "cd android && ./gradlew assembleRelease",
"run-android": "react-native run-android",
"run-ios": "react-native run-ios --simulator \"iPhone 11\""
"run-ios": "react-native run-ios --simulator \"iPhone 14 Pro Max\"",
"run-device": "react-native run-ios --device",
"ios": "react-native run-ios --simulator \"iPhone 14 Pro Max\""
},
"rnpm": {
"assets": [
@ -18,51 +20,66 @@
]
},
"dependencies": {
"@invertase/react-native-apple-authentication": "^1.1.2",
"@react-native-community/cameraroll": "^1.2.1",
"@react-native-community/datetimepicker": "^3.0.2",
"@react-native-community/toolbar-android": "^0.2.1",
"@react-native-firebase/app": "^17.3.2",
"@react-native-firebase/messaging": "^17.3.2",
"apisauce": "^1.1.0",
"deprecated-react-native-listview": "^0.0.5",
"i18n-js": "^3.5.1",
"intl": "^1.2.5",
"jetifier": "^2.0.0",
"moment": "^2.24.0",
"native-base": "^2.13.8",
"react": "16.9.0",
"react-native": "0.61.5",
"react-native": "^0.63",
"react-native-action-sheet": "^2.2.0",
"react-native-appearance": "^0.2.2",
"react-native-camera": "^4.2.1",
"react-native-countdown-component": "^2.7.1",
"react-native-device-info": "^5.5.7",
"react-native-dropdown-picker": "^5.4.6",
"react-native-easy-grid": "^0.2.2",
"react-native-elastic-image-slider": "^1.0.0",
"react-native-elements": "^1.2.0",
"react-native-fast-image": "^8.1.5",
"react-native-fbsdk": "^1.1.2",
"react-native-firebase": "^5.5.6",
"react-native-gesture-handler": "^1.4.1",
"react-native-hyperlink": "^0.0.16",
"react-native-image-crop-picker": "0.25.3",
"react-native-image-crop-picker": "^0.32.2",
"react-native-image-slider-show": "^1.0.3",
"react-native-image-slideshow": "^1.0.1",
"react-native-image-view": "^2.1.5",
"react-native-linear-gradient": "^2.5.6",
"react-native-modal-datetime-picker": "^7.5.0",
"react-native-pager-view": "^5.4.25",
"react-native-permissions": "^3.6.1",
"react-native-picker-dropdown": "^0.1.2",
"react-native-qrcode": "^0.2.7",
"react-native-qrcode-scanner": "^1.5.5",
"react-native-qrcode-svg": "^5.2.0",
"react-native-render-html": "^4.1.2",
"react-native-screens": "^2.7.0",
"react-native-searchable-dropdown": "^1.1.1",
"react-native-signature-canvas": "^2.4.0",
"react-native-signature-canvas": "^4.4.1",
"react-native-signature-pad": "^0.1.0",
"react-native-snap-carousel": "^3.8.0",
"react-native-splash-screen": "^3.2.0",
"react-native-svg": "^9.9.3",
"react-native-switch-toggle": "^1.1.0",
"react-native-tab-view": "^3.1.1",
"react-native-toast-message": "^2.2.1",
"react-native-vector-icons": "^6.6.0",
"react-native-view-shot": "^3.0.2",
"react-native-webview": "^9.4.0",
"react-native-webview": "^11.23.0",
"react-navigation": "^3.3.0",
"react-redux": "^7.1.1",
"react-select2-native": "^1.3.0",
"redux": "^4.0.4",
"redux-persist": "^5.10.0",
"redux-persist-transform-encrypt": "^2.0.1"
"redux-persist-transform-encrypt": "^2.0.1",
"rn-tooltip": "^2.0.0"
},
"devDependencies": {
"@babel/core": "^7.6.0",
@ -71,7 +88,7 @@
"babel-jest": "^24.9.0",
"eslint": "^6.3.0",
"jest": "^24.9.0",
"metro-react-native-babel-preset": "^0.56.0",
"metro-react-native-babel-preset": "^0.59.0",
"react-test-renderer": "16.8.6"
},
"jest": {

View File

@ -2,9 +2,11 @@ import Api from './api'
import { Platform } from 'react-native'
import Config from 'src/utils/Config'
import DeviceInfo from 'react-native-device-info'
import ApiPowerCondo from "./apiPowerCondo";
import moment from "moment";
export const getUserProfile = () => {
return Api.get('/me');
return Api.get('/mobile/me');
}
export const testConnect = () => {
@ -12,7 +14,7 @@ export const testConnect = () => {
}
export const registerDevice = (pushToken) => {
return Api.post('/register/device', {
return Api.post('/mobile/register/device', {
push_token: pushToken,
uid: DeviceInfo.getUniqueId(),
brand: DeviceInfo.getBrand(),
@ -21,43 +23,56 @@ export const registerDevice = (pushToken) => {
}
export const register = (user) => {
return Api.post('/register',
user
);
const formData = new FormData()
for (let k in user) {
formData.append(k, user[k])
}
return Api.post('/register', formData );
}
export const login = (params) => {
return Api.post('/login',
params = {
...params,
uid: DeviceInfo.getUniqueId(),
brand: DeviceInfo.getBrand(),
model: DeviceInfo.getModel()
}
return Api.post('/api/login',
params
);
}
export const logout = () => {
return Api.post('/api/logout');
}
export const dashboard = (params) => {
return Api.get('/me/dashboard');
return Api.get('/mobile/me/dashboard');
}
export const getNews = (params) => {
return Api.get('/news');
return Api.get('/mobile/news');
}
export const getNewsPage = (page = 1) => {
return Api.get('/news?page='+page);
return Api.get('/mobile/news?page='+page);
}
export const getNewsDetail = (news_id) => {
return Api.get('/news/'+news_id);
return Api.get('/mobile/news/'+news_id);
}
export const getNewsByProject = (project_id) => {
return Api.get('/news_projects/'+project_id);
return Api.get('/mobile/news-projects/'+project_id);
}
export const project = (keyword) => {
return Api.get('/project');
return Api.get('/mobile/project');
}
export const getBuildingByProjectId = (project_id) => {
return Api.get(`/project/${project_id}/building`);
return Api.get(`/mobile/project/${project_id}/building`);
}
export const room = (project_id) => {
@ -71,13 +86,13 @@ export const roomdetail = (room_id) => {
}
export const payment = (user_id) => {
return Api.get('/payment', {
return Api.get('/mobile/me/invoice', {
user_id: user_id
});
}
export const payment_detail = (payments_id) => {
return Api.get('/payment/'+payments_id);
return Api.get('/mobile/payment/'+payments_id);
}
export const total_payment = (user_id) => {
@ -85,51 +100,52 @@ export const total_payment = (user_id) => {
}
export const edit_profile = (user) => {
const formData = new FormData()
for (let k in user) {
formData.append(k, user[k])
}
return Api.post('/me/profile', formData );
// const formData = new FormData()
// for (let k in user) {
// formData.append(k, user[k])
// }
// let formDataParts = formData._parts ? formData._parts : formData;
return Api.post('/mobile/me/profile', user );
}
export const get_notification = (user_id, page) => {
return Api.get('/notification', {
return Api.get('/mobile/notification', {
user_id: user_id,
page: page
})
}
export const read_notification = (noti_id) => {
return Api.post('/notification',{noti_id: noti_id})
return Api.post('/mobile/notification',{noti_id: noti_id})
}
export const count_notification = (user_id) => {
return Api.get('/notification/count', {
return Api.get('/mobile/notification/count', {
user_id: user_id
})
}
export const getSubscription = (customer_id,type) => {
return Api.get('/subscription', {
return Api.get('/mobile/subscription', {
customer_id: customer_id,
type: type,
})
}
export const postSubscription = (customer_id,type) => {
return Api.post('/subscription', {
return Api.post('/mobile/subscription', {
customer_id: customer_id,
type: type,
})
}
export const getProductList = () => {
return Api.get('/product');
return Api.get('/mobile/product');
}
export const getProductDetail = (product_id) => {
return Api.get('/product/'+product_id);
return Api.get('/mobile/product/'+product_id);
}
export const getServices = () => {
@ -148,8 +164,8 @@ export const getRepairList = (service_id) => {
return Api.get('/repair');
}
export const getRepairById = (repair_id) => {
return Api.get('/repair/'+repair_id);
export const getRepairById = (repair_id, type = '') => {
return Api.get(`/repair/${repair_id}?self_room=${(type === 'effect_responsible' ? 'true' : 'false')}`);
}
export const postRepair = (param) => {
@ -166,7 +182,8 @@ export const postSuggestion = (params) => {
for (let k in params) {
formData.append(k, params[k])
}
return Api.post('/suggestion',formData)
let newFormData = formData._parts ? formData._parts : formData;
return Api.post('/mobile/suggestion', newFormData)
}
export const postSuggestionLogin = (params) => {
@ -174,22 +191,22 @@ export const postSuggestionLogin = (params) => {
for (let k in params) {
formData.append(k, params[k])
}
return Api.post('/service_suggestion',formData)
return Api.post('/mobile/service-suggestion',formData)
}
//Question & Answer
export const getConversation = () => {
return Api.get('/conversation');
return Api.get('/mobile/conversation');
}
export const postConversation = (param) => {
return Api.post('/conversation/messages',param);
return Api.post('/mobile/conversation/messages',param);
}
//Object & Message
export const getObjectMessage = () => {
return Api.get('/parcel');
return Api.get('/mobile/parcel');
}
export const postSignatureImage = (params) => {
@ -197,29 +214,29 @@ export const postSignatureImage = (params) => {
for (let k in params) {
formData.append(k, params[k])
}
return Api.post('/parcel',formData);
return Api.post('/mobile/parcel',formData);
}
export const getObjectMessageByID = (id) => {
return Api.get(`/parcel/${id}`);
return Api.get(`/mobile/parcel/${id}`);
}
//Meter
export const getMeterList = () => {
return Api.get('/meter');
return Api.get('/mobile/meter');
}
export const getRoomSlideList = (roon_id) => {
return Api.get('/meter?room_id='+roon_id);
return Api.get('/mobile/meter?room_id='+roon_id);
}
export const postMeter = (params) => {
const formData = new FormData()
for (let k in params) {
formData.append(k, params[k])
}
// const formData = new FormData()
// for (let k in params) {
// formData.append(k, params[k])
// }
return Api.post('/meter',formData);
return Api.post('/mobile/meter',params);
}
export const postMeterImage = (params) => {
@ -228,7 +245,7 @@ export const postMeterImage = (params) => {
formData.append(k, params[k])
}
return Api.post('/ocr',formData);
return Api.post('/mobile/ocr',formData);
}
export const disconnectFacebook = (user) => {
@ -236,3 +253,126 @@ export const disconnectFacebook = (user) => {
user
);
}
export const getRoomParcel = (room_no) => {
return Api.get('/check_room_parcel?room_no='+room_no);
}
export const setPaymentLater = () => {
return Api.get('/set_payment_later')
}
export const setFillInMeterLater = () => {
return Api.get('/set_record_meter_later')
}
export const checkPaymentMeter = () => {
return Api.get('/mobile/me/check-payment-meter')
}
export const getRoomUser = () => {
return Api.get('/mobile/get_room_user');
}
export function cancelRepair(id) {
return Api.post('/repair/cancel', {id: id})
}
export function postEvaluateRepair(params) {
return Api.post('/repair/point', params)
}
export function setLanguage(language) {
return Api.post('/mobile/me/set-language', {language: language})
}
export function getRoomPowerCondo(project_id, customer_id) {
return Api.get(`/api/project/${project_id}/room/list/customer?customer_id=${customer_id}`)
}
export function getRoomSelfPowerCondo() {
return Api.get(`/mobile/me/room`)
}
export function getRepairDropdownList(query) {
return Api.get(`/api/dropdowns?name=${query}`)
}
export function getRepairListPowerCondo(project_id) {
return Api.get(`/api/project/${project_id}/maintenance-setting`)
}
export function sendRequestRepair(project_id, body){
return Api.post(`/api/project/${project_id}/maintenance`, body)
}
export function sendMoveOutData(project_id, body){
return Api.post(`/api/project/${project_id}/move-out`, body)
}
export function getListReward(category_id='') {
category_id = category_id ? category_id : '';
return Api.get(`/mobile/reward?category_id=${category_id}`)
}
export function getRewardDetail(id, is_my_reward) {
let url = is_my_reward ? '/mobile/me/reward' : '/mobile/reward';
return Api.get(`${url}/${id}`)
}
export function getListMyReward(type_id = '', category_id = '', customer_finance_id='') {
return Api.get(`/mobile/me/reward?type=${type_id}&category_id=${category_id}&customer_finance_id=${customer_finance_id}`)
}
export function getHistoryRedeemPoint(datetime) {
datetime = moment(datetime, 'MMMM YYYY')
return Api.get(`/mobile/me/history-point?month=${datetime.format('M')}&year=${datetime.format('YYYY')}`)
}
export function redeemReward(id) {
return Api.post(`/mobile/redeem/${id}`)
}
export function scanReward(id, code) {
return Api.post(`/mobile/coupon/${id}/qr/${code}`)
}
export function usedCoupon(id) {
return Api.post(`/mobile/coupon/${id}/qr`)
}
export function useMyReward(id) {
return Api.post(`/mobile/me/reward/${id}`)
}
export function forgetPassword(mobile) {
return Api.post('/api/forget-password', {mobile});
}
export function sendVerifyOTP(token, otp) {
return Api.post(`/api/verify-otp/${token}`, {otp})
}
export function getRewardTermAndCondition(reward_id) {
return Api.get(`/mobile/reward/${reward_id}/term-and-condition`);
}
export function useRentalDiscount(coupon_id, payment_id){
return Api.post(`/mobile/coupon/${coupon_id}/discount/${payment_id}`)
}
export function removeRentalDiscount(coupon_id, payment_id){
return Api.delete(`/mobile/coupon/${coupon_id}/discount/${payment_id}`)
}
export function getLevelMembership(){
return Api.get(`/mobile/me/loyalty`);
}
export function getLevelMemberDetail(){
return Api.get(`/mobile/loyalty/privilege`)
}
export function getPointExpire(){
return Api.get('/mobile/me/expired-point')
}

View File

@ -1,8 +1,7 @@
import { create } from 'apisauce'
import Config from 'src/utils/Config'
import DeviceInfo from 'react-native-device-info'
import { Alert, NetInfo, Platform } from 'react-native'
import NavigationService from 'src/utils/NavigationService'
import { Alert, Platform } from 'react-native'
// import { strings as t } from '../i18n'
// import { userLogout } from 'src/redux/app/action'
@ -11,15 +10,26 @@ import NavigationService from 'src/utils/NavigationService'
let store
const Api = create({
baseURL: Config.API_BASE_URL,
// baseURL: Config.API_BASE_URL_PROD,
baseURL: Config.API_BASE_URL_POWER_CONDO_DEV,
headers: {
'X-Frame-Options': 'sameorigin',
'X-App-Version': DeviceInfo.getVersion(),
'X-Device-OS': Platform.OS,
'X-Device-Version': Platform.Version,
'Content-Type': 'application/json'
}
})
export function setBaseUrl (baseUrl) {
Api.setBaseURL(baseUrl)
}
export function setBaseUrlByServerMode (mode) {
// Api.setBaseURL(mode === 'production' ? Config.API_BASE_URL_PROD : Config.API_BASE_URL_DEV)
Api.setBaseURL(mode === 'production' ? Config.API_BASE_URL_PROD : Config.API_BASE_URL_POWER_CONDO_DEV)
}
DeviceInfo.getDeviceName().then(name => {
Api.setHeader('X-Device-Name', name)
})
@ -29,11 +39,11 @@ Api.addRequestTransform(request => {
})
if (process.env.NODE_ENV !== 'production') {
Api.addRequestTransform(request => {
console.info('--> [' + request.method + '] ' + Api.getBaseURL() + request.url,request.params, request.data)
console.info('header --' + request.url +' -- ', request.headers)
console.info('--> [' + request.method + '] ' + Api.getBaseURL() + request.url, request.params, request.data)
console.info('header --' + request.url + ' -- ', request.headers)
})
Api.addMonitor(response => {
console.info('<-- ' + response.status + ' --- ' + response.config.url,response)
console.info('<-- ' + response.status + ' --- ' + response.config.url, response)
})
}
@ -49,8 +59,7 @@ Api.addMonitor(response => {
case 'SERVER_ERROR':
case 'CANCEL_ERROR':
case 'CLIENT_ERROR': // 4XX
if (response.status === 401) {
// store.dispatch(userLogout)
/*if (response.status === 401) {
Alert.alert('Session timeout', 'Please login again to continue using application', [
{
text: 'ok',
@ -58,20 +67,20 @@ Api.addMonitor(response => {
// NavigationService.navigate('AppLoading')
}
}
], {cancelable: false})
], { cancelable: false })
return
}
}*/
// Alert.alert(null, 'error_getting_data', [{text: 'ok'}])
break
}
}
})
export function setStore(reduxStore) {
export function setStore (reduxStore) {
store = reduxStore
}
export function setToken(token) {
export function setToken (token) {
Api.setHeader('Authorization', 'Bearer ' + token)
}
@ -79,11 +88,11 @@ export function setLanguage (languageCode) {
Api.setHeader('language', languageCode)
}
export function clearToken() {
export function clearToken () {
Api.deleteHeader('Authorization')
}
export function setLocation(lat, lng) {
export function setLocation (lat, lng) {
Api.setHeader('X-Current-Latitude', lat.toString() || '0.0')
Api.setHeader('X-Current-Longitude', lng.toString() || '0.0')
}

68
src/api/apiPowerCondo.js Normal file
View File

@ -0,0 +1,68 @@
import { create } from 'apisauce'
import Config from 'src/utils/Config'
import DeviceInfo from 'react-native-device-info'
import { Platform } from 'react-native'
const ApiPowerCondo = create({
baseURL: Config.API_BASE_URL_POWER_CONDO_DEV,
headers: {
'X-Frame-Options': 'sameorigin',
'X-App-Version': DeviceInfo.getVersion(),
'X-Device-OS': Platform.OS,
'X-Device-Version': Platform.Version,
'Content-Type': 'application/json'
}
})
DeviceInfo.getDeviceName().then(name => {
ApiPowerCondo.setHeader('X-Device-Name', name)
})
ApiPowerCondo.addRequestTransform(request => {
// request.headers['X-App-Locale'] = I18n.locale
})
if (process.env.NODE_ENV !== 'production') {
ApiPowerCondo.addRequestTransform(request => {
console.info('--> [' + request.method + '] ' + ApiPowerCondo.getBaseURL() + request.url, request.params, request.data)
console.info('header --' + request.url + ' -- ', request.headers)
})
ApiPowerCondo.addMonitor(response => {
console.info('<-- ' + response.status + ' --- ' + response.config.url, response)
})
}
// error alert monitor
ApiPowerCondo.addMonitor(response => {
if (!response.ok) {
switch (response.problem) {
case 'CONNECTION_ERROR':
case 'NETWORK_ERROR':
case 'TIMEOUT_ERROR':
// Alert.alert('error_internet_title', 'error_internet_message', [{text: 'ok'}])
break
case 'SERVER_ERROR':
case 'CANCEL_ERROR':
case 'CLIENT_ERROR': // 4XX
break
}
}
})
export function setTokenPowerCondo (token) {
ApiPowerCondo.setHeader('Authorization', 'Bearer ' + token)
}
export function setLanguagePowerCondo (languageCode) {
ApiPowerCondo.setHeader('language', languageCode)
}
export function clearTokenPowerCondo () {
ApiPowerCondo.deleteHeader('Authorization')
}
export function setLocationPowerCondo (lat, lng) {
ApiPowerCondo.setHeader('X-Current-Latitude', lat.toString() || '0.0')
ApiPowerCondo.setHeader('X-Current-Longitude', lng.toString() || '0.0')
}
export default ApiPowerCondo

View File

@ -0,0 +1,83 @@
import appleAuth, {
AppleAuthRequestOperation,
AppleAuthRequestScope,
AppleAuthCredentialState,
} from '@invertase/react-native-apple-authentication';
import { setToken } from '../api/api'
import { store } from '../redux/store'
import {appSetToken, appSetUser} from '../redux/app/action';
import {login, register} from '../api/UserApi';
import {Alert} from 'react-native';
export const signinApple = async (onSuccess) => {
try {
const requestOptions = {
requestedOperation: AppleAuthRequestOperation.LOGIN,
requestedScopes: [AppleAuthRequestScope.EMAIL, AppleAuthRequestScope.FULL_NAME],
}
// register({
// ...this.props.user,
// device_id: deviceId
// }).then((res) => {
//
// });
// login
/* const { user } = await appleAuth.performRequest(requestOptions);
console.log(user) */
// register
const appleAuthRequestResponse = await appleAuth.performRequest({
requestedOperation: AppleAuthRequestOperation.LOGIN,
requestedScopes: [AppleAuthRequestScope.EMAIL, AppleAuthRequestScope.FULL_NAME],
})
console.log(appleAuthRequestResponse)
// get current authentication state for user
// /!\ This method must be tested on a real device. On the iOS simulator it always throws an error
// use credentialState response to ensure the user is authenticated
if (AppleAuthCredentialState.AUTHORIZED) {
// user is authenticated
// sent and login
let params = {
identityToken: appleAuthRequestResponse.identityToken,
authorizationCode: appleAuthRequestResponse.authorizationCode,
email_apple: appleAuthRequestResponse.email
}
login(params)
.then(async (res) => {
if(res.status == 500){
Alert.alert('','ไม่สามารถเชื่อมต่อกับเซิฟเวอร์ได้ กรุณาลองใหม่อีกครั้ง')
return
}
if (res.ok) {
if (res.data.token) {
//Alert.alert('Connect with Facebook Success')
setToken(res.data.token)
store.dispatch(appSetToken(res.data.token))
store.dispatch(appSetUser(res.data.user))
onSuccess && onSuccess()
}
} else {
if(res.data.msg != null){
Alert.alert('',res.data.msg)
}
}
})
}
} catch (e) {
console.log(e);
if (e.code === 'ERR_CANCELED') {
// handle that the user canceled the sign-in flow
} else {
// handle other errors
}
}
}

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react'
import { TextInput, View } from 'react-native'
import Icon from 'src/components/Icon'
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome'
import Text from 'src/components/Text';
export class CustomInput extends Component {
@ -8,10 +9,30 @@ export class CustomInput extends Component {
let props = this.props
return (
<View style={[styles.container, props.style]}>
{props.iconName && <View style={styles.icon}>
{/* {
props.iconType === 'fontAwesome' ?
props.iconName && <View style={styles.icon}>
<FontAwesomeIcon name={props.iconName} size={16} color={props.iconColor || 'white'}/>
</View>
:
props.iconName && <View style={styles.icon}>
<Icon name={props.iconName} size={16} color={props.iconColor || 'white'}> </Icon>
</View>
} */}
{ props.iconName ?
props.iconType ?
<View style={styles.icon}>
<FontAwesomeIcon name={props.iconName} size={18} color={props.iconColor || 'white'}> </FontAwesomeIcon>
</View>
:
<View style={styles.icon}>
<Icon name={props.iconName} size={16} color={props.iconColor || 'white'}> </Icon>
</View>
: <View></View>
}
{props.labelName && <View style={styles.icon}>
<Text style={{ color: props.labelColor || 'rgba(0, 0, 0, 0.5)' }}>{props.labelName}</Text>
</View>
@ -20,10 +41,12 @@ export class CustomInput extends Component {
<View style={{ flex: 1 , justifyContent:'center'}}>
<TextInput
{...props}
style={{ padding: 7, textAlign: 'right', color: props.afterInput || 'white', fontFamily: 'Prompt-Regular' }}
style={{ padding: 7, textAlign: 'right', color: props.afterInput || 'white', fontFamily: 'Prompt-Regular', ...props.textInputStyles }}
secureTextEntry={props.secureTextEntry}
textAlign={props.inputTextAlign || 'right'}
placeholder={props.placeholder} value={props.value} />
placeholder={props.placeholder}
value={props.value}
/>
</View>
</View>
)

View File

@ -5,6 +5,7 @@ import { login, disconnectFacebook } from '../api/UserApi'
import { store } from '../redux/store'
import { Alert } from 'react-native'
import NavigationService from '../utils/NavigationService';
import messaging from "@react-native-firebase/messaging";
let requestManager = new GraphRequestManager();
@ -33,10 +34,22 @@ export function loginWithFacebook(onSuccess){
);
}
function loginAccessTokenToServer(accessToken,onSuccess){
async function loginAccessTokenToServer(accessToken,onSuccess){
const fcm = messaging();
if (!await fcm.hasPermission()) {
try {
await messaging().requestPermission();
} catch (error) {
}
}
const fcmToken = await messaging().getAPNSToken();
let params = {
access_token: accessToken,
fcm_token: fcmToken
}
login(params)
.then(async (res) => {
if(res.status == 500){
@ -66,13 +79,15 @@ export function logoutFacebook() {
export function disconnectWithFacebook(onSuccess){
AccessToken.getCurrentAccessToken().then(
(data) => {
AccessToken.getCurrentAccessToken()
.then((data) => {
console.log("AccessToken.getCurrentAccessToken():")
console.log(data)
const accessToken = data.accessToken.toString()
let accessToken = null;
if(data && data.accessToken){
accessToken = data.accessToken.toString();
}
//console.log("accessToken:")
//console.log(accessToken)
@ -91,20 +106,7 @@ export function disconnectWithFacebook(onSuccess){
}
if (res.ok) {
Alert.alert('Disconnect with Facebook Success')
// if (res.data.token) {
// setToken(res.data.token)
// store.dispatch(appSetToken(res.data.token))
this.state.user.fb_token = null
this.state.user.fb_is_link = 'f'
//Alert.alert(this.state.user)
//console.log('console.log(this.state.user):')
//console.log(this.state.user)
// store.dispatch(appSetUser(this.state.user))
// store.dispatch(appSetFacebook('f'))
onSuccess && onSuccess()
// }
onSuccess && onSuccess();
} else {
if(res.data.msg != null){
Alert.alert('',res.data.msg)

53
src/components/Popup.js Normal file
View File

@ -0,0 +1,53 @@
import React, { Component } from 'react';
import { View, Modal, TouchableOpacity } from 'react-native';
import Text from "./Text";
export default class Popup extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<View>
<Modal animationType="none"
transparent={true}
visible={this.props.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{flex:1,backgroundColor:'#00000080',justifyContent:'center',alignItems:'center'}}>
<View style={{width: '90%',backgroundColor:'white',borderRadius:5,paddingVertical: 27, paddingHorizontal: 17}}>
<Text style={[{color:'#2C7C0B',fontSize: 18}, this.props.styleTitle ? this.props.styleTitle : {}]}>
{this.props.title}
</Text>
{
this.props.message && <Text style={[{color:'#00000080',fontSize: 14,marginVertical: 15}, this.props.styleMessage ? this.props.styleMessage : {}]}>{this.props.message}</Text>
}
<View style={[{flexDirection:'row', width: '100%', justifyContent: 'center', marginTop: 30}, this.props.styleFooter ? this.props.styleFooter : {}]}>
<View style={{width: '50%'}}>
{
this.props.onCancel &&
<TouchableOpacity onPress={() => {this.props.onCancel()}}>
<Text style={{color:'#269A21',fontSize: 14, textAlign: 'center'}}>Cancel</Text>
</TouchableOpacity>
}
</View>
<View style={{width: '50%'}}>
<TouchableOpacity onPress={() => {this.props.onConfirm && this.props.onConfirm()}}>
<Text style={[{color:'#269A21',fontSize: 14,textAlign: 'center'}, this.props.styleConfirmBtn ? this.props.styleConfirmBtn : {} ]}>
OK
</Text>
</TouchableOpacity>
</View>
</View>
</View>
</View>
</Modal>
</View>
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import { switchLanguage } from 'src/utils/i18n'
import { setLanguage } from '../../api/api'
import { setBaseUrlByServerMode, setLanguage } from '../../api/api'
// action type
export const ACTION_APP_SET_TOKEN = 'APP_SET_TOKEN'
@ -14,9 +14,12 @@ export const ACTION_APP_CHANGE_NOTIFICATION = 'ACTION_APP_CHANGE_NOTIFICATION'
export const ACTION_APP_SET_PROJECT_ID = 'ACTION_APP_SET_PROJECT_ID'
export const ACTION_APP_CLEAN_PROJECT_ID = 'ACTION_APP_CLEAN_PROJECT_ID'
export const ACTION_APP_SET_LANGUAGE = 'ACTION_APP_SET_LANGUAGE'
export const ACTION_APP_SET_SERVER_MODE = 'ACTION_APP_SET_SERVER_MODE'
export const ACTION_SET_POPUP_NOTIFICATION = 'ACTION_SET_POPUP_NOTIFICATION'
// action creator
export function appSetToken (token) {
console.log('token appSetToken >>>>>>>>>>>>>>> ', token)
return {
type: ACTION_APP_SET_TOKEN,
token
@ -97,3 +100,18 @@ export function appSetLanguage (langCode) {
lang: langCode
}
}
export function setServerMode (mode) {
setBaseUrlByServerMode(mode)
return {
type: ACTION_APP_SET_SERVER_MODE,
mode
}
}
export function setPopupNotification(data) {
return {
type: ACTION_SET_POPUP_NOTIFICATION,
popup_notification : data
}
}

View File

@ -11,6 +11,8 @@ import {
ACTION_APP_SET_PROJECT_ID,
ACTION_APP_CLEAN_PROJECT_ID,
ACTION_APP_SET_LANGUAGE,
ACTION_APP_SET_SERVER_MODE,
ACTION_SET_POPUP_NOTIFICATION
} from './action'
const initialState = {
@ -21,34 +23,39 @@ const initialState = {
notification: null,
project_id: null,
lang: null,
};
server_mode: 'production',
}
export default function (state = initialState, action) {
switch (action.type) {
case ACTION_APP_SET_LANGUAGE:
return { ...state, lang: action.lang }
case ACTION_APP_SET_TOKEN:
return { ...state, token: action.token };
return { ...state, token: action.token }
case ACTION_APP_CLEAN_TOKEN:
return { ...state, token: null };
return { ...state, token: null }
case ACTION_APP_SET_PUSH_TOKEN:
return { ...state, push_token: action.pushToken };
return { ...state, push_token: action.pushToken }
case ACTION_APP_SET_DEVICE:
return { ...state, device: action.device };
return { ...state, device: action.device }
case ACTION_APP_CLEAN_DEVICE:
return { ...state, device: null };
return { ...state, device: null }
case ACTION_APP_SET_USER:
return { ...state, user: action.user };
return { ...state, user: action.user }
case ACTION_APP_CLEAN_USER:
return { ...state, user: null };
return { ...state, user: null }
case ACTION_APP_SET_NOTIFICATION:
return { ...state, count_noti: action.count_noti };
return { ...state, count_noti: action.count_noti }
case ACTION_APP_CHANGE_NOTIFICATION:
return { ...state, notification: action.notification };
return { ...state, notification: action.notification }
case ACTION_APP_SET_PROJECT_ID:
return { ...state, project_id: action.project_id };
return { ...state, project_id: action.project_id }
case ACTION_APP_CLEAN_PROJECT_ID:
return { ...state, project_id: null };
return { ...state, project_id: null }
case ACTION_APP_SET_SERVER_MODE:
return { ...state, server_mode: action.mode }
case ACTION_SET_POPUP_NOTIFICATION:
return { ...state, popup_notification: action.popup_notification }
default:
return state
}

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { appSetDevice, appSetPushToken, appSetToken, appSetUser } from '../../redux/app/action'
import {appSetDevice, appSetPushToken, appSetToken, appSetUser} from '../../redux/app/action'
import { connect } from 'react-redux'
import { View } from 'react-native'
import { switchLanguage } from '../../utils/i18n'
@ -24,7 +24,8 @@ class AppLoading extends Component {
const mapStateToProps = state => {
return {
lang: state.app.lang
lang: state.app.lang,
user: state.app.user
}
}
const setUser = dispatch => bindActionCreators({ appSetToken, appSetPushToken, appSetDevice, appSetUser }, dispatch)

View File

@ -5,6 +5,7 @@ import { useDispatch } from 'react-redux'
import { appSetLanguage } from '../../redux/app/action'
import { BackgroundImage_RegisterForm } from '../../components/BackgroundImage_RegisterForm'
import LinearGradient from 'react-native-linear-gradient'
import {setLanguage} from "../../api/UserApi";
const languages = [
{ code: 'th', name: 'ภาษาไทย' },
@ -18,7 +19,18 @@ export default function ({ navigation }) {
function selectLanguage (code) {
dispatch(appSetLanguage(code))
if(code === 'th'){
code = 'th_TH';
}
setLanguage(code)
.then(res => {
if(res.success){
navigation.navigate('HomeScreen')
}else{
navigation.navigate('HomeScreen')
}
})
}
return <LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{

View File

@ -24,7 +24,8 @@ import {appSetDevice, appSetPushToken, appSetToken, appSetUser} from "../../redu
import moment from "moment";
import IndicatorLoading from '../../components/IndicatorLoading';
import { t } from 'src/utils/i18n'
import parseDateLocale from 'src/utils/parseDateLocale';
import { NavigationEvents } from 'react-navigation'
const { height, width } = Dimensions.get('window')
function ItemOrder({title,cost,description,type}){
@ -98,9 +99,7 @@ class BillScreen extends Component {
this.checkstatusBill = this.checkstatusBill.bind(this)
}
componentDidMount() {
this.setState({isLoading: true})
if(this.props.user){
getData = () => {
payment(this.props.user.id)
.then(res => {
if(res.ok){
@ -156,7 +155,10 @@ class BillScreen extends Component {
let date_now = moment()
let findTimeout = array_payment.find((item) => {return moment(item.due_at) == date_now})
let findTimeout = array_payment.find((item) => {
console.log('item >>> ',item)
return moment(item.due_at) == date_now
})
//check bill timeout
if(findTimeout !== undefined){
this.setState({
@ -181,65 +183,61 @@ class BillScreen extends Component {
})
}
})
}
}
// if(res.ok){
// let sum_payment = [];
// let array_payment = [];
// let sum_cost_room = res.data.sum_cost_room;
// let all_payment = res.data.payment_room_period;
// let room_number_array = [];
getMonth(period_month){
let new_month = 'มกราคม'
switch (period_month) {
case '01':
new_month = 'มกราคม';
break;
case '02':
new_month = 'กุมภาพันธ์';
break;
case '03':
new_month = 'มีนาคม';
break;
case '04':
new_month = 'เมษายน';
break;
case '05':
new_month = 'พฤษภาคม';
break;
case '06':
new_month = 'มิถุนายน';
break;
case '07':
new_month = 'กรกฎาคม';
break;
case '08':
new_month = 'สิงหาคม';
break;
case '09':
new_month = 'กันยายน';
break;
case '10':
new_month = 'ตุลาคม';
break;
case '11':
new_month = 'พฤศจิกายน';
break;
case '12':
new_month = 'ธันวาคม';
break;
default:
new_month = 'มกราคม';
break;
}
// if(Object.keys(sum_cost_room).length > 0) {
// Object.keys(sum_cost_room).map((sum_cost) => {
// sum_payment.push({
// total_cost : sum_cost_room[sum_cost].total_cost,
// room: sum_cost_room[sum_cost].room,
// room_id: sum_cost_room[sum_cost].room_id,
// project: sum_cost_room[sum_cost].project,
// due_at: sum_cost_room[sum_cost].due_at,
// }
// )
// room_number_array.push(sum_cost_room[sum_cost].room_id)
// })
return new_month;
// let first_room = room_number_array && room_number_array.length > 0 && room_number_array[0];
// array_payment = all_payment && all_payment.length > 0 && all_payment.filter((payment)=>{
// return payment.room_id === first_room
// });
// let date_now = moment()
// let findTimeout = array_payment && array_payment.length > 0 && array_payment.find((item) => {return moment(item.due_date) == date_now})
// //check bill timeout
// if(findTimeout !== undefined){
// this.setState({
// isCanPay: false
// })
// }
// }
// this.setState({
// isLoading: false,
// payment: array_payment,
// sum_payment: sum_payment,
// all_payment,
// room_number_array
// })
// }else {
// this.setState({
// isLoading: false
// })
// }
// })
}
getTitle (period) {
let period_month = moment(period, "MM/Y").format('MM');
let period_year = parseInt(moment(period, "MM/Y").format('Y')) + 543;
let new_month = 'มกราคม';
let new_period = new_month + ' ' + period_year;
new_month = this.getMonth(period_month)
new_period = new_month + ' ' + period_year;
let period_month = moment(period, "MM/Y").format('MMMM');
let period_year = parseInt(moment(period, "MM/Y").locale('en').format('Y'));
let new_month = '';
let new_period = period_month + ' ' + period_year;
return new_period;
}
@ -254,7 +252,7 @@ class BillScreen extends Component {
return true
}
checkstatusBill(data,boolDate){
checkstatusBill(data, isOverdue){
if(data.status == 'paid'){
return <TouchableOpacity style={{backgroundColor:data.status === 'pending' ? '#145EB3' : 'white',
height: 32,width: 103,justifyContent:'center',alignItems:'center',borderRadius:5,
@ -263,13 +261,13 @@ class BillScreen extends Component {
disabled={data.status === 'pending' ? false : true}
onPress={() => {
this.state.isCanPay ?
data.status === 'pending' && this.props.navigation.navigate('Payment',{payment_id:data.id})
data.status === 'pending' && this.props.navigation.navigate('PaymentDetail',{payment_id:data.payment_id})
: Alert.alert(null, 'รายการค้างชำระของคุณ เกินกำหนดชำระ กรุณาติดต่อสำนักงานบริการลูกค้า',[{text: t('ok')}])
}}>
<Text style={{ color: data.status === 'pending' ? 'white' : 'rgba(0, 0, 0, 0.25)'}}>{data.status === 'pending' ? 'จ่ายเงิน' : 'จ่ายแล้ว'}</Text>
<Text style={{ color: data.status === 'pending' ? 'white' : 'rgba(0, 0, 0, 0.25)'}}>{data.status === 'pending' ? 'ดูเพิ่มเติม' : 'จ่ายแล้ว'}</Text>
</TouchableOpacity>
}else{
if(!boolDate){
if(isOverdue){
return <View>
<Text style={{ color: 'red',borderWidth:1,borderColor:'#00000040',borderRadius:5,paddingHorizontal:6}}>{'เกินกำหนดชำระ'}</Text>
</View>
@ -281,10 +279,10 @@ class BillScreen extends Component {
disabled={data.status === 'pending' ? false : true}
onPress={() => {
this.state.isCanPay ?
data.status === 'pending' && this.props.navigation.navigate('Payment',{payment_id:data.id})
data.status === 'pending' && this.props.navigation.navigate('PaymentDetail',{payment_id:data.payment_id})
: Alert.alert(null, 'รายการค้างชำระของคุณ เกินกำหนดชำระ กรุณาติดต่อสำนักงานบริการลูกค้า',[{text: t('ok')}])
}}>
<Text style={{ color: data.status === 'pending' ? 'white' : 'rgba(0, 0, 0, 0.25)'}}>{data.status === 'pending' ? 'จ่ายเงิน' : 'จ่ายแล้ว'}</Text>
<Text style={{ color: data.status === 'pending' ? 'white' : 'rgba(0, 0, 0, 0.25)'}}>{data.status === 'pending' ? 'ดูเพิ่มเติม' : 'จ่ายแล้ว'}</Text>
</TouchableOpacity>
}
}
@ -292,19 +290,39 @@ class BillScreen extends Component {
_renderHeader(data, expanded) {
// if(data.room_id == this.state.sum_payment[this.state.activePage].room.id){
let checkBool = this.checkDueDate(data.due_at == null || data.due_at == undefined ? moment() : data.due_at)
let checkBool = this.checkDueDate(data.due_date == null || data.due_date == undefined ? moment() : data.due_date)
return (
<View style={{flex:1,flexDirection:'row',backgroundColor:'#B8DAAA',height: 64,borderBottomWidth:1,borderBottomColor:'white',alignItems:'center',justifyContent:'space-between',paddingHorizontal:16}}>
<View style={{justifyContent:'center',flex:1}}>
<Text>{t('month')} {this.getTitle(data.period)}</Text>
{/*<Text>{t('month')} {parseDateLocale(moment(data.period, 'MM/Y'), 'MMMM Y')}</Text>*/}
<Text>{t('payment_no')} : {data.invoice_code}</Text>
<View style={{flexDirection:'row',alignItems:'center',justifyContent:'space-between'}}>
{expanded || data.status != 'pending' ? <Text /> : <Text note style={styles.colorTextPayment}>{t('outstanding_balance')} {data.total_cost}</Text>}
{
data.status !== 'complete' && <Text note style={styles.colorTextPayment}>{t('outstanding_balance')} {data.total_cost}</Text>
}
{expanded || <Text style={{fontSize:10,marginRight:16}}>{t('view_more')}</Text>}
</View>
</View>
{
this.checkstatusBill(data,checkBool)
}
{/*{
this.checkstatusBill(data, data.is_overdue)
}*/}
<TouchableOpacity style={{
backgroundColor: data.status === 'complete' ? 'lightgrey' : '#145EB3',
height: 32,width: 103,
justifyContent:'center',
alignItems:'center',
borderRadius:5,
borderColor: data.status === 'complete' ? 'grey' : '',
borderWidth: data.status === 'complete' ? 1 : 0
}}
onPress={ data.status === 'complete' ? () => {} : () => { this.props.navigation.navigate('PaymentDetail',{payment_id: data.id, room: data.room_id})}}
disabled={ data.status === 'complete'}
>
<Text style={{ color: 'white' }}>{data.status === 'complete' ? 'จ่ายแล้ว' : 'ดูเพิ่มเติม'}</Text>
</TouchableOpacity>
{/* {
checkBool ?
data.enable_qr &&
@ -331,51 +349,51 @@ class BillScreen extends Component {
}
_renderContent(data) {
let water_cost = 0;
let electrict_cost = 0;
let room_cost = 0;
let service_cost = 0;
let date_payment = '';
let extra_info = '';
let d = moment(data.created_at).format('D')
let m = moment(data.created_at).format('MM')
let y = parseInt(moment(data.created_at).format('Y')) + 543
date_payment = d + ' ' + this.getMonth(m) + ' ' + y
// let water_cost = 0;
// let electrict_cost = 0;
// let room_cost = 0;
// let service_cost = 0;
// let date_payment = '';
// let extra_info = '';
// let d = moment(data.created_at).format('D')
// let m = moment(data.created_at).format('MM')
// let y = parseInt(moment(data.created_at).format('Y')) + 543
//date_payment = d + ' ' + this.getMonth(m) + ' ' + y
let descriptionRoom = '-'
let descriptionWater = '-'
let descriptionElec = '-'
let descriptionService = '-'
// let descriptionRoom = '-'
// let descriptionWater = '-'
// let descriptionElec = '-'
// let descriptionService = '-'
// console.log('check data ----------> ',data)
if(data.details){
data.details.map((det) => {
if(det.sequence === 1){
room_cost = det.cost
room_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionRoom = det.descript == '' ? '-' : det.descript
}
// if(data.details){
// data.details.map((det) => {
// if(det.sequence === 1){
// room_cost = det.cost
// room_extra_info = det.extra_info != null ? det.extra_info : ''
// descriptionRoom = det.descript == '' ? '-' : det.descript
// }
if(det.sequence === 2){
water_cost = det.cost
water_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionWater = det.descript == '' ? '-' : det.descript
}
// if(det.sequence === 2){
// water_cost = det.cost
// water_extra_info = det.extra_info != null ? det.extra_info : ''
// descriptionWater = det.descript == '' ? '-' : det.descript
// }
if(det.sequence === 3){
electrict_cost = det.cost
electrict_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionElec = det.descript == '' ? '-' : det.descript
}
// if(det.sequence === 3){
// electrict_cost = det.cost
// electrict_extra_info = det.extra_info != null ? det.extra_info : ''
// descriptionElec = det.descript == '' ? '-' : det.descript
// }
if(det.sequence === 4){
service_cost = det.cost
service_extra_info = det.extra_info != null ? det.extra_info : ''
descriptionService = det.descript == '' ? '-' : det.descript
}
})
}
// if(det.sequence === 4){
// service_cost = det.cost
// service_extra_info = det.extra_info != null ? det.extra_info : ''
// descriptionService = det.descript == '' ? '-' : det.descript
// }
// })
// }
return (
<View>
@ -462,7 +480,7 @@ class BillScreen extends Component {
item.due_at !== null
? (
<View style={{height:24,backgroundColor: '#FF2D55',justifyContent:'center',alignItems:'center'}}>
<Text style={{ fontSize: 12, color: 'white'}}>{t('please_pay_before')} {this.getDueDate(item.due_at)}</Text>
<Text style={{ fontSize: 12, color: 'white'}}>{t('please_pay_within')} {this.getDueDate(item.due_at)}</Text>
</View>
)
: null
@ -490,11 +508,12 @@ class BillScreen extends Component {
roomFilter(index){
let payment_exits = this.state.all_payment;
let another_room = this.state.room_number_array[index];
let payment_array = payment_exits.filter((obj)=>{
return Object.keys(obj).reduce((acc, curr)=>{
return obj.room_id === another_room
}, false);
});
let payment_array = [];
if(payment_exits && payment_exits.length > 0){
payment_array = payment_exits.filter((payment) => {
return payment.room_id === another_room;
})
}
this.state.payment = payment_array;
}
@ -504,6 +523,15 @@ class BillScreen extends Component {
return (
<SafeAreaView style={{flex: 1}}>
<ScrollView contentContainerStyle={styles.contentContainer}>
<NavigationEvents
onDidFocus={() => {
this.setState({
isLoading: true
}, () => {
this.getData()
})
}}
/>
<View style={{ alignItems: 'center'}}>
{
this.state.sum_payment.length == 0 &&
@ -528,7 +556,7 @@ class BillScreen extends Component {
<View style={{flex:1}}>
<Accordion
dataArray={ this.state.payment }
expanded={this.state.payment.length - 1}
expanded={this.state.payment && this.state.payment.length > 0 ? this.state.payment.length - 1 : []}
renderHeader={(data, expanded) => { return this._renderHeader(data, expanded) }}
renderContent={(data) => { return this._renderContent(data) }} />
</View>

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react'
import {ScrollView, StyleSheet, Image, TouchableOpacity, Alert, PermissionsAndroid, ImageBackground, Platform} from "react-native";
import {ScrollView, StyleSheet, TouchableOpacity, Alert, PermissionsAndroid, ImageBackground, Platform} from "react-native";
import CameraRoll from "@react-native-community/cameraroll";
import {View} from "native-base";
import Text from '../../components/Text';
@ -8,6 +8,7 @@ import ViewShot, { captureRef } from "react-native-view-shot";
import IndicatorLoading from '../../components/IndicatorLoading';
import QRCode from 'react-native-qrcode-svg';
import { t } from '../../utils/i18n';
import Image from 'react-native-fast-image'
class PaymentScreen extends Component {
constructor(props) {
@ -26,11 +27,24 @@ class PaymentScreen extends Component {
this.setState({isLoading:true})
payment_detail(this.state.payment_id)
.then( res => {
if(res.data && res.data.success){
this.setState({
payment_data: res.data
},() => {
this.setState({isLoading: false})
})
}else {
Alert.alert(res.data.message, '', [{
text: 'ok',
onPress: () => {
this.setState({
isLoading: false
}, () => {
this.props.navigation.goBack()
})
}
}])
}
})
};
@ -81,16 +95,16 @@ class PaymentScreen extends Component {
render(){
return(
<ImageBackground source={require('../../../assets/images/tree2.png')} style={{width: '100%', height: '100%', backgroundColor:'#EEFFD7'}}>
<ViewShot style={{flex: 1}} options={{format: "jpg", quality: 1}} ref={ref => this.viewshot = ref}>
<ScrollView contentContainerStyle={styles.contentContainer}>
<View style={{flex: 1}}>
<View style={{ alignItems: 'center', padding:20}}>
<ViewShot style={{width: '100%',alignItems:'center'}} options={{format: "jpg", quality: 1}} ref={ref => this.viewshot = ref}>
<View style={{backgroundColor:'white', borderRadius:10,width: '90%',alignItems:'center'}}>
<View style={{width: '100%',backgroundColor:'#29558D',height: 55,borderTopLeftRadius:10,borderTopEndRadius:10,alignItems:'center',justifyContent:'center'}}>
<View style={styles.QrContainer}>
<View style={styles.headerQr}>
<Image source={require('../../../assets/images/icon_payment.png')} style={{height: 40}} resizeMode={'contain'}/>
</View>
<Image source={require('../../../assets/images/icon_promptpay.png')} style={{height: 24,marginVertical: 18}} resizeMode={'contain'}/>
<Text style={{fontSize: 18,color:'#00420A'}}>{t('scan_to_pay')}</Text>
<Image source={require('../../../assets/images/icon_promptpay.png')} style={{height: 35, marginVertical: 18}} resizeMode={'contain'}/>
<Text style={{fontSize: 18,color:'#00420A', textAlign: 'center'}}>{t('scan_to_pay')}</Text>
<View style={{flex: 0.9, alignItems: 'center'}}>
{/* <Image source={{uri: this.state.payment_data.qr}} style={{flex: 1}} resizeMode="contain"/> */}
<View style={{paddingVertical:10}}>
<QRCode
value={this.state.payment_data.qr}
@ -98,6 +112,7 @@ class PaymentScreen extends Component {
color='black'
backgroundColor='white'/>
</View>
<View style={{alignItems: 'center'}}>
<Text style={{fontSize: 12,color:'#000000'}}>อบญช : {this.state.payment_data.receiver_name}</Text>
<Text style={{fontSize: 12,color:'#000000'}}>{t('account')} : {this.state.payment_data.receiver_account}</Text>
<Text style={{fontSize: 10,color:'#00000080'}}>{t('ref_no')}: { this.state.payment_data.payment != null && this.state.payment_data.payment.reference}</Text>
@ -108,15 +123,17 @@ class PaymentScreen extends Component {
<View style={{margin: 10,height:1,width: '100%',backgroundColor:'#D7D7D7'}}/>
<Text style={{fontSize: 10,color:'#00000080',marginBottom: 10}}>Accepts all banks | {t('support_all_bank')}</Text>
</View>
</ViewShot>
</View>
<View style={{alignItems: 'center', paddingHorizontal:20}}>
<TouchableOpacity style={{backgroundColor:'#269A21',width: '90%',height: 40,justifyContent:'center',alignItems:'center',borderRadius:5}} onPress={this.snapScreen}>
<Text style={{color:'white',fontSize:14}}>{t('save')}</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
</ViewShot>
<View style={{flex: 0.1, justifyContent: 'center'}}>
<TouchableOpacity style={{backgroundColor:'#269A21',height: 40,justifyContent:'center',alignItems:'center',borderRadius:5, marginHorizontal: 20}}
onPress={this.snapScreen}>
<Text style={{color:'white',fontSize:14}}>{t('save')}</Text>
</TouchableOpacity>
</View>
<IndicatorLoading loadingVisible={this.state.isLoading}/>
</ImageBackground>
)
@ -133,11 +150,24 @@ const styles = StyleSheet.create({
alignItems: 'center'
},
contentContainer: {
paddingVertical: 0,
flex:1
flex:1,
padding: 20
},
colorTextPayment: {
color: '#7CBB33'
},
QrContainer: {
flex: 1,
backgroundColor:'white',
borderRadius:10
},
headerQr: {
width: '100%',
backgroundColor:'#29558D',
height: 55,
borderTopLeftRadius:10,
borderTopEndRadius:10,
justifyContent:'center'
}
})

View File

@ -0,0 +1,197 @@
import React, {Component} from "react";
import { ImageBackground, View, StyleSheet, Text, TouchableOpacity } from "react-native";
import { payment_detail, removeRentalDiscount } from "../../api/UserApi";
import IndicatorLoading from "../../components/IndicatorLoading";
import IconMaterial from 'react-native-vector-icons/MaterialCommunityIcons'
import { FlatList, NavigationEvents } from "react-navigation";
class PaymentConfirm extends Component {
constructor(props){
super(props);
this.state = {
payment_id: null,
payment: null,
isLoading: false
}
}
componentDidMount(){
const payment_id = this.props.navigation.getParam('payment_id');
const room = this.props.navigation.getParam('room');
this.setState({
room
})
if(payment_id){
this.setState({
payment_id
}, () => {
this.getPayment()
})
}
}
getPayment = () => {
this.setState({
isLoading: true
}, () => {
payment_detail(this.state.payment_id)
.then(res => {
if(res.data && res.data.success){
this.setState({
payment: res.data,
isLoading: false
})
}else {
this.setState({
isLoading: false
})
}
})
})
}
renderItem = (item) => {
return (
<View style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', marginBottom: 8}}>
<Text style={[styles.mainText, {color: 'black'}]}>{item.cost_name}</Text>
<Text style={[styles.mainText, {color: '#7CBB33', fontWeight: '500'}]}>{parseFloat(item.total).toLocaleString()} บาท</Text>
</View>
)
}
removeCoupon = () => {
this.setState({
isLoading: true
}, () => {
removeRentalDiscount(this.state.payment.coupon.id, this.state.payment_id)
.then(res => {
if(res.data && res.data.success){
this.setState({
payment_id: res.data.payment_id
}, () => {
this.getPayment()
this.setState({
isLoading: false
})
})
}else {
this.setState({
isLoading: false
})
}
})
})
}
render(){
return (
<ImageBackground source={require('../../../assets/images/tree2.png')} style={styles.ImageBackground}>
<IndicatorLoading loadingVisible={this.state.isLoading}/>
<NavigationEvents
onDidFocus={() => {
this.setState({
isLoading: true
}, () => {
this.getPayment()
})
}}
/>
<View style={{padding: 16, flex: 0.9}}>
<View style={styles.detialContainer}>
<View style={styles.borderBottom}>
<Text style={[styles.mainText, {fontSize: 18, textAlign: 'center'}]}>ใบตงหน</Text>
{
this.state.payment && this.state.payment.detail.length > 0 &&
<Text style={[styles.mainText, {fontSize: 14, textAlign: 'center'}]}>
อง {this.state.room ? this.state.room : ''}
</Text>
}
</View>
<View style={styles.borderBottom}>
<View style={{flexDirection: 'row', display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8}}>
<Text style={[styles.mainText, {color: '#269A21'}]}>รายการ</Text>
<Text style={[styles.mainText, {color: '#269A21'}]}>จำนวนเง</Text>
</View>
{
this.state.payment && this.state.payment.detail && this.state.payment.detail.length > 0 &&
<FlatList
data={this.state.payment.detail}
renderItem={({ item }) => this.renderItem(item)}
pagingEnabled={true}
extraData={this.state}
keyExtractor={this._keyExtractor}
/>
}
</View>
<View style={{flexDirection: 'row', justifyContent: 'flex-end', marginTop: 10, paddingHorizontal: 10}}>
<Text style={[styles.mainText, {textAlign: 'right',}]}>รวม</Text>
<Text style={[styles.mainText, {fontWeight: '500', paddingLeft: 10}]}>
{this.state.payment && this.state.payment.total_cost ? parseFloat(this.state.payment.total_cost).toLocaleString() : 0} บาท
</Text>
</View>
<View style={[styles.useCoupon]}>
<Text style={[styles.mainText, {fontSize: 16}]}>ใชปองสวนลด </Text>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={[styles.mainText, {fontSize: 16, marginRight: 5}]}>
{
this.state.payment && this.state.payment.coupon && this.state.payment.coupon.value ? this.state.payment.coupon.value : 0
} บาท
</Text>
<TouchableOpacity onPress={() => this.removeCoupon()}>
<IconMaterial name="close-circle-outline" size={18} color="#FF2D55"/>
</TouchableOpacity>
</View>
</View>
</View>
</View>
<View style={{padding: 16, flex: 0.1}}>
<TouchableOpacity style={{backgroundColor: '#145EB3', paddingVertical: 12, borderRadius: 5}}
onPress={() => this.props.navigation.navigate('Payment', {payment_id: this.state.payment_id })}
>
<Text style={{color: 'white', textAlign: 'center', fontFamily: 'Prompt-Regular'}}>นยนรายการและชำระเง</Text>
</TouchableOpacity>
</View>
</ImageBackground>
)
}
}
const styles = StyleSheet.create({
ImageBackground: {
backgroundColor:'#EEFFD7',
flex: 1
},
detialContainer: {
backgroundColor: 'white',
borderRadius: 5,
padding: 15
},
borderBottom: {
borderBottomWidth: 1,
borderColor: '#EAEAF4',
padding: 10
},
mainText: {
color: '#00420A',
fontFamily: 'Prompt-Regular'
},
useCoupon: {
marginTop: 10,
backgroundColor: '#E6FFC2',
paddingHorizontal: 10,
paddingVertical: 10,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
}
})
export default PaymentConfirm;

View File

@ -0,0 +1,381 @@
import React, {Component} from 'react'
import { View, StyleSheet, ImageBackground, Text, FlatList, TouchableOpacity, Modal, Alert, ScrollView } from 'react-native';
import FastImage from 'react-native-fast-image';
import { getListMyReward, payment_detail, useRentalDiscount, removeRentalDiscount } from '../../api/UserApi';
import IndicatorLoading from '../../components/IndicatorLoading';
import IconFontawesome from 'react-native-vector-icons/FontAwesome'
import IconMaterial from "react-native-vector-icons/MaterialCommunityIcons";
import { NavigationEvents } from 'react-navigation';
class PaymentDetail extends Component {
constructor(props){
super(props);
this.state = {
payment: null,
coupon_list: [],
modalVisible: false,
isLoading: false,
couponSelected: null,
couponHighlight: null,
payment_id: null,
room: null
}
}
componentDidMount(){
const payment_id = this.props.navigation.getParam('payment_id', null);
const room = this.props.navigation.getParam('room', null);
this.setState({
room
})
if(payment_id){
this.setState({
isLoading: true,
payment_id
})
}
}
getPaymentDetail = () => {
payment_detail(this.state.payment_id)
.then(res => {
if(res.data && res.data.success){
this.setState({
payment: res.data,
isLoading: false
}, () => {
this.getCouponList()
})
}else {
this.setState({
isLoading: false
})
}
})
}
getCouponList = () => {
getListMyReward('', 1, this.state.payment.is_coupon ? this.state.payment_id : '')
.then(res => {
if(res.data && res.data.data){
let coupon = null;
if(res.data.data.length > 0 && this.state.payment && this.state.payment.coupon && this.state.payment.coupon.id){
coupon = res.data.data.filter((item) => item.id === this.state.payment.coupon.id);
if(coupon && coupon.length > 0){
coupon = coupon[0]
}
}
this.setState({
coupon_list: res.data.data,
isLoading: false,
couponSelected: coupon
})
}else{
this.setState({
isLoading: false
})
}
})
}
renderItem = (item) => {
return (
<View style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', marginBottom: 8}}>
<Text style={[styles.mainText, {color: 'black'}]}>{item.cost_name}</Text>
<Text style={[styles.mainText, {color: '#7CBB33', fontWeight: '500'}]}>{parseFloat(item.total).toLocaleString()} บาท</Text>
</View>
)
}
_keyExtractor = (item, index) => 'payment_detail_'+index
visibleCoupon = () => {
this.setState({
modalVisible: true
})
}
useCoupon = () => {
this.setState({
modalVisible: false,
isLoading: true
}, () => {
useRentalDiscount(this.state.couponHighlight.id, this.state.payment_id)
.then(res => {
if(res.data && res.data.success){
this.setState({
couponSelected: this.state.couponHighlight,
// isLoading: false,
modalVisible: false,
payment_id: res.data.new_payment_id,
}, () => {
setTimeout(() => {
this.getPaymentDetail()
}, 3000)
})
}else {
let message = res.data && res.data.message ? res.data.message : 'ใช้คูปองส่วนลดไม่สำเร็จ'
Alert.alert(message)
this.setState({
isLoading: false
})
}
})
})
}
removeCoupon = () => {
this.setState({
isLoading: true
}, () => {
removeRentalDiscount(this.state.couponSelected.id, this.state.payment_id)
.then(res => {
if(res.data && res.data.success){
this.setState({
payment_id: res.data.payment_id
}, () => {
this.getPaymentDetail()
this.setState({
isLoading: false
})
})
}else {
this.setState({
isLoading: false
})
}
})
})
}
render(){
const room = this.state.room
return (
<ImageBackground source={require('../../../assets/images/tree2.png')} style={styles.ImageBackground}>
<NavigationEvents
onDidFocus={() => {
this.setState({
isLoading: true
}, () => {
this.getPaymentDetail()
})
}}
/>
<IndicatorLoading loadingVisible={this.state.isLoading}/>
<View style={{padding: 16, flex: 0.9}}>
<ScrollView contentContainerStyle={styles.detialContainer}>
<View style={styles.borderBottom}>
<Text style={[styles.mainText, {fontSize: 18, textAlign: 'center'}]}>ใบตงหน</Text>
{
this.state.payment && this.state.payment.detail.length > 0 &&
<Text style={[styles.mainText, {fontSize: 14, textAlign: 'center'}]}>
อง {room ? room : ''}
</Text>
}
</View>
<View style={styles.borderBottom}>
<View style={{flexDirection: 'row', display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8}}>
<Text style={[styles.mainText, {color: '#269A21'}]}>รายการ</Text>
<Text style={[styles.mainText, {color: '#269A21'}]}>จำนวนเง</Text>
</View>
{
this.state.payment && this.state.payment.detail && this.state.payment.detail.length > 0 &&
<FlatList
data={this.state.payment.detail}
renderItem={({ item }) => this.renderItem(item)}
pagingEnabled={true}
extraData={this.state}
keyExtractor={this._keyExtractor}
/>
}
</View>
<View style={{flexDirection: 'row', justifyContent: 'flex-end', marginTop: 10, paddingHorizontal: 10}}>
<Text style={[styles.mainText, {textAlign: 'right',}]}>รวม</Text>
<Text style={[styles.mainText, {fontWeight: '500', paddingLeft: 10}]}>
{this.state.payment && this.state.payment.total_cost ? parseFloat(this.state.payment.total_cost).toLocaleString() : 0} บาท
</Text>
</View>
{
!this.state.couponSelected &&
<View style={styles.useCouponContainer}>
<View>
<Text style={[styles.mainText, {fontSize: 16}]}>ใชปองสวนลด</Text>
{
this.state.coupon_list?.length === 0 && <Text style={[styles.mainText, {color: 'red', fontSize: 10}]}>ไมพบรายการคปอง</Text>
}
</View>
<TouchableOpacity style={{backgroundColor: this.state.coupon_list?.length === 0 ? 'lightgrey' : '#269A21', borderRadius: 5}}
onPress={() => this.visibleCoupon()}
disabled={this.state.coupon_list?.length === 0}
>
<Text style={[styles.mainText, {color: 'white', paddingHorizontal: 25, paddingVertical: 8}]}>เลอก</Text>
</TouchableOpacity>
</View>
}
{
this.state.couponSelected &&
<View>
<Text style={[styles.mainText, {fontSize: 16, marginVertical: 10}]}>ปองสวนลดทเลอก</Text>
<View style={styles.couponCard}>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<FastImage source={{uri: this.state.couponSelected.image_reward}} style={{width: 50, height: 50 }} resizeMode={'contain'}/>
<View style={{marginLeft: 10}}>
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Text style={[styles.mainText, {fontSize: 16, marginRight: 5}]}>{this.state.couponSelected.reward_name}</Text>
<Text style={[styles.mainText, {fontSize: 16}]}>{this.state.couponSelected.value} {this.state.couponSelected.discount_type === 'percent' ? '%' : 'บาท'}</Text>
</View>
<Text style={[styles.mainText, {color: '#FF2D55'}]}>{this.state.couponSelected.detail}</Text>
</View>
</View>
<TouchableOpacity onPress={() => this.removeCoupon()}>
<IconMaterial name="close-circle-outline" size={18} color="#FF2D55"/>
</TouchableOpacity>
</View>
</View>
}
</ScrollView>
</View>
<View style={{padding: 16, flex: 0.1}}>
<TouchableOpacity style={{backgroundColor: '#145EB3', paddingVertical: 12, borderRadius: 5}}
// onPress={() => this.props.navigation.navigate('PaymentConfirm', {payment_id: this.state.new_payment_id ? this.state.new_payment_id : this.state.payment_id, room: this.state.room})}
onPress={() => this.props.navigation.navigate('Payment', {payment_id: this.state.payment_id })}
>
<Text style={{color: 'white', textAlign: 'center', fontFamily: 'Prompt-Regular'}}>นยนรายการและชำระเง</Text>
</TouchableOpacity>
</View>
<Modal animationType="none"
transparent={true}
visible={this.state.modalVisible}
>
<View style={styles.couponContainer}>
<View style={styles.couponBox}>
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Text style={[styles.mainText, {fontSize: 18, marginBottom: 10}]}>
เลอกคปองสวนลด
</Text>
<TouchableOpacity onPress={() => this.setState({modalVisible: false, couponHighlight: null})}>
<IconFontawesome name="close" color="#269A21" size={16}/>
</TouchableOpacity>
</View>
<FlatList
data={this.state.coupon_list}
renderItem={({ item }) => (
<TouchableOpacity
style={[styles.couponCard, this.state.couponHighlight && this.state.couponHighlight.id === item.id ? {}: {backgroundColor: '#FAFAFA', borderColor: '#00000040'}]}
onPress={() => this.setState({couponHighlight: item})}>
<FastImage source={{uri: item.image_reward}} style={{width: 50, height: 50 }} resizeMode={'contain'}/>
<View style={{marginLeft: 10, flex: 1}}>
<View style={{flexDirection: 'row', flex: 1, justifyContent: 'space-between'}}>
<Text style={[styles.mainText, {fontSize: 16, flex: 0.7}]}>{item.reward_name}</Text>
<Text style={[styles.mainText, {fontSize: 16, flex: 0.3}]}>{item.value} {item.discount_type === 'percent' ? '%' : 'บาท'} </Text>
</View>
<Text style={[styles.mainText, {color: '#FF2D55'}]}>{item.detail}</Text>
</View>
</TouchableOpacity>
)}
pagingEnabled={true}
extraData={this.state.coupon_list}
keyExtractor={(item, index) => 'coupon_' + index}
ListEmptyComponent={() =>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center', margin: 16,padding:16,borderRadius:5,backgroundColor:'white'}}>
<Text style={{fontSize: 16}}> ไมพบรายการคปอง </Text>
</View>
}
/>
<TouchableOpacity
onPress={() => this.useCoupon()}
style={{
backgroundColor: this.state.coupon_list.length === 0 || this.state.couponHighlight === null ? 'grey' : '#269A21',
marginTop: 10,
borderRadius: 5
}}
disabled={this.state.coupon_list.length === 0 || this.state.couponHighlight === null}
>
<Text style={[styles.mainText, {color: 'white', paddingVertical: 12, textAlign: 'center'}]}>
นยนการใชปอง
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</ImageBackground>
)
}
}
const styles = StyleSheet.create({
contentContainer: {
backgroundColor: '#EEFFD7',
paddingVertical: 0,
flexGrow: 1,
},
detialContainer: {
backgroundColor: 'white',
borderRadius: 5,
padding: 15,
flexGrow: 1
},
ImageBackground: {
backgroundColor:'#EEFFD7',
flex: 1
},
borderBottom: {
borderBottomWidth: 1,
borderColor: '#EAEAF4',
padding: 10
},
mainText: {
color: '#00420A',
fontFamily: 'Prompt-Regular'
},
useCouponContainer: {
backgroundColor: '#E6FFC2',
padding: 8,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginTop: 16
},
couponContainer: {
flex:1,
backgroundColor:'#00000080',
justifyContent:'center',
alignItems:'center'
},
couponBox: {
width: '90%',
maxHeight: '80%',
backgroundColor:'white',
borderRadius:5,
padding:17
},
couponCard: {
backgroundColor: '#FDFFA2',
padding: 8,
// flex: 1,
flexDirection: 'row',
borderLeftWidth: 4,
borderColor: '#FFCC00',
borderRadius: 5,
marginBottom: 8,
justifyContent: 'space-between',
alignItems: 'center',
}
})
export default PaymentDetail;

View File

@ -0,0 +1,169 @@
import React, {Component} from 'react';
import {KeyboardAvoidingView, SafeAreaView, ScrollView, View, Text, Alert, TouchableOpacity} from 'react-native'
import LinearGradient from 'react-native-linear-gradient';
import { forgetPassword } from '../../api/UserApi';
import { BackgroundImage } from '../../components/BackgroundImage';
import { CustomButton } from '../../components/CustomButton';
import { CustomInput } from '../../components/CustomInput';
import IndicatorLoading from '../../components/IndicatorLoading';
import { t } from '../../utils/i18n';
class ForgetPasswordScreen extends Component {
constructor(props) {
super(props)
this.state = {
mobile: '',
isLoading: false
}
}
submitForgetPassword = () => {
this.setState({
isLoading: true
}, () => {
forgetPassword(this.state.mobile)
.then(res => {
if(res.data && res.data.success){
Alert.alert('ทำรายการสำเร็จ', 'กรุณาตรวจสอบ OTP ที่ส่งไปยังเบอร์โทรศัพท์ของท่าน', [
{
text: 'OK',
onPress: () => {
this.props.navigation.navigate('VerifyOTP', {token: res.data.token, mobile: this.state.mobile})
this.setState({
isLoading: false
})
}
}
])
}else {
let message = res && res.data && res.data.message ? res.data.message : '';
Alert.alert('ทำรายการไม่สำเร็จ', message)
this.setState({
isLoading: false
})
}
})
})
}
render() {
return (
<SafeAreaView style={{flex: 1}}>
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
flex: 1,
width: null,
height: null,
resizeMode: 'cover'
}}>
<BackgroundImage>
<KeyboardAvoidingView style={{flex:1}}
keyboardVerticalOffset={Platform.OS == 'ios' ? 70 : 0}
behavior={Platform.OS == 'ios' ? "padding" : ""} enabled>
<View style={styles.container}>
<View style={{flex: 0.7}}>
<View style={{flex: 1, flexDirection: 'column', justifyContent: 'center'}}>
<View>
<Text style={[styles.textStyle, {fontSize: 28, fontFamily: 'Prompt-Bold'}]}>
มรหสผาน
</Text>
<Text style={[styles.textStyle, {fontSize: 18, fontFamily: 'Prompt-Regular'}]}>
กรณากรอกเบอรโทรศพท
</Text>
<Text style={[styles.textStyle, {fontSize: 18, fontFamily: 'Prompt-Regular'}]}>
เพอรบรห OTP ทาง SMS
</Text>
{/* <Text style={[styles.textStyle, {fontSize: 18}]}>
กรณากรอกอเมล ระบบจะสงลงก
</Text>
<Text style={[styles.textStyle, {fontSize: 18}]}>
สำหรบเปลยนรหสผานใหบทาน
</Text> */}
</View>
<View style={{marginVertical: 20}}>
<View style={{flexDirection: 'row', flex: 1}}>
<CustomInput
onChangeText={(e) => {
this.setState({
mobile: e
})
}}
inputTextAlign={'left'}
iconName={'phone'}
iconType={'fontAwesome'}
placeholder={t('phone')}
placeholderTextColor={'#FFFFFF40'}
keyboardType='numeric'
maxLength={10}
style={styles.form_input} />
</View>
</View>
</View>
</View>
<View style={{flex: 0.3, width: '100%', marginTop: 20}}>
<View style={{height: 48}}>
<TouchableOpacity onPress={this.submitForgetPassword}
style={styles.btnSubmit}
disabled={this.state.mobile === ''}
>
<Text style={styles.textBtnSubmit}>
{t('confirm')}
</Text>
</TouchableOpacity>
</View>
</View>
</View>
<View style={{position: 'absolute', bottom: 20, flex: 1, width: '100%', flexDirection: 'row', justifyContent:'center'}}>
<Text style={{color: 'white', textAlign: 'center', marginRight: 10, fontSize: 14, fontFamily: 'Prompt-Regular'}}>กลบไปย</Text>
<TouchableOpacity onPress={() => this.props.navigation.navigate('HomeScreen')}>
<Text style={{color: 'white', fontFamily: 'Prompt-Bold', fontSize: 14}}>ลงชอเขาใชงาน</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</BackgroundImage>
<IndicatorLoading loadingVisible={this.state.isLoading}/>
</LinearGradient>
</SafeAreaView>
)
};
}
const styles = {
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 40
},
textStyle: {
color: 'white',
textAlign: 'center'
},
form_input: {
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'white', borderRadius: 30,
borderWidth: 1,
width: '100%'
},
btnSubmit: {
backgroundColor: 'white',
borderRadius: 30,
paddingVertical: 10,
paddingHorizontal: 50,
flex: 1,
height: 50,
},
textBtnSubmit: {
color: '#2470A1',
fontFamily: 'Prompt-Bold',
fontSize: 16,
textAlign: 'center'
}
}
export default ForgetPasswordScreen;

View File

@ -0,0 +1,84 @@
import React, { Component } from "react";
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, Clipboard, ToastAndroid, Alert } from "react-native";
import LinearGradient from "react-native-linear-gradient";
import { BackgroundImage } from "../../components/BackgroundImage";
import AntdIcon from 'react-native-vector-icons/AntDesign'
import Toast from "react-native-toast-message";
class PasswordCode extends Component {
constructor(props) {
super(props);
this.state = {
password: this.props.navigation.getParam('password', null)
}
}
handleCopy = () => {
Toast.show({
type: 'success',
text1: 'Copy success!',
});
Clipboard.setString(this.state.password)
}
render () {
return (
<SafeAreaView style={{flex: 1}}>
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
flex: 1,
width: null,
height: null,
resizeMode: 'cover'
}}>
<BackgroundImage>
<View style={styles.container}>
<Text style={[styles.fontPromtBold, {color: 'white', fontSize: 30, marginBottom: 10}]}>รหสผานใหม</Text>
<Text style={{color: 'white', fontSize: 18, fontFamily: 'Prompt-Regular'}}>คลกทรหสผานเพอคดลอก</Text>
<Text style={{color: 'white', fontSize: 18, marginBottom: 50, fontFamily: 'Prompt-Regular'}}>เพอนำไปใชในการเขาสระบบ</Text>
<TouchableOpacity onPress={this.handleCopy}>
<View style={styles.code_form}>
<Text style={{color: 'white', fontSize: 25, fontFamily: 'Prompt-Regular', marginRight: 10}}>
{this.state.password}
</Text>
<AntdIcon name="copy1" color="white" style={{fontSize: 30}}/>
</View>
</TouchableOpacity>
</View>
<View style={{position: 'absolute', bottom: 20, flex: 1, width: '100%', flexDirection: 'row', justifyContent:'center'}}>
<Text style={{color: 'white', textAlign: 'center', marginRight: 10, fontSize: 14, fontFamily: 'Prompt-Regular'}}>กลบไปย</Text>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Login')}>
<Text style={{color: 'white', fontFamily: 'Prompt-Bold', fontSize: 14}}>ลงชอเขาใชงาน</Text>
</TouchableOpacity>
</View>
</BackgroundImage>
</LinearGradient>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 40
},
code_form: {
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'white', borderRadius: 30,
borderWidth: 1,
width: '100%',
paddingVertical: 10,
paddingHorizontal: 15,
flexDirection: 'row',
alignItems: 'center'
},
fontPromtBold: {
fontFamily: 'Prompt-Bold'
}
})
export default PasswordCode;

View File

@ -0,0 +1,221 @@
import React, {Component} from 'react';
import { Alert, KeyboardAvoidingView, SafeAreaView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import { BackgroundImage } from '../../components/BackgroundImage';
import { CustomInput } from '../../components/CustomInput';
import { t } from '../../utils/i18n';
import IndicatorLoading from '../../components/IndicatorLoading';
import { sendVerifyOTP, forgetPassword } from '../../api/UserApi';
class VerifyOTP extends Component {
constructor(props) {
super(props)
this.state = {
otp: null,
is_loading: false,
seconds: 300000,
minuteLeft: 5,
secondLeft: 0,
token: this.props.navigation.getParam('token', null),
mobile: this.props.navigation.getParam('mobile', null)
}
this.countdownTimer = null
}
componentDidMount () {
this.startTimer()
}
componentWillUnmount () {
this.countdownTimer = null
}
startTimer = () => {
if (this.countdownTimer) return;
this.countdownTimer = setInterval(() => {
if(this.state.seconds > 0) {
this.setState({
seconds: this.state.seconds - 1000
}, () => {
let min = parseInt(this.state.seconds/60000)
this.setState({
minuteLeft: min
})
let min_to_ms = min * 60000
let sec = parseInt((this.state.seconds - min_to_ms)/1000)
this.setState({
secondLeft: sec
})
})
}else {
clearInterval(this.interval);
this.countdownTimer = null;
}
}, 1000);
};
submitVerifyOTP = () => {
this.setState({
is_loading: true
}, async () => {
await sendVerifyOTP(this.state.token, this.state.otp).then(res => {
if(res && res.data && res.data.success) {
this.setState({
is_loading: false
}, () => {
this.props.navigation.navigate('PasswordCode', {password: res.data.password})
})
}else {
let message = res && res.data && res.data.message ? res.data.message : ''
Alert.alert('ทำรายการไม่สำเร็จ', message)
this.setState({
is_loading: false
})
}
})
})
}
resentRequestOTP = async () => {
this.setState({
is_loading: true
}, () => {
forgetPassword(this.state.mobile)
.then(res => {
if(res.data && res.data.success){
Alert.alert('ทำรายการสำเร็จ', 'กรุณาตรวจสอบ OTP ที่ส่งไปยังเบอร์โทรศัพท์ของท่าน', [
{
text: 'OK',
onPress: () => {
this.setState({
is_loading: false,
seconds: 300000,
minuteLeft: 5,
secondLeft: 0,
}, () => {
this.startTimer()
})
}
}
])
}else {
let message = res && res.data && res.data.message ? res.data.message : '';
Alert.alert('ทำรายการไม่สำเร็จ', message)
this.setState({
is_loading: false
})
}
})
})
}
render() {
return (
<SafeAreaView style={{flex: 1}}>
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
flex: 1,
width: null,
height: null,
resizeMode: 'cover'
}}>
<BackgroundImage>
<KeyboardAvoidingView style={{flex:1}}
keyboardVerticalOffset={Platform.OS == 'ios' ? 70 : 0}
behavior={Platform.OS == 'ios' ? "padding" : ""} enabled>
<View style={styles.container}>
<View style={{flex: 0.7, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<Text style={[styles.fontPromtBold, {color: 'white', fontSize: 30}]}>นยนรห OTP</Text>
<Text style={[styles.fontPromtRegular, {color: 'white', fontSize: 18, textAlign: 'center'}]}>กรณากรอกรห OTP</Text>
<Text style={[styles.fontPromtRegular, {color: 'white', fontSize: 18, marginBottom: 50, textAlign: 'center'}]}>งไปทเบอร {this.state.mobile}</Text>
<CustomInput
onChangeText={(e) => {
this.setState({
otp: e
})
}}
inputTextAlign={'center'}
placeholder={'XXXX'}
placeholderTextColor={'#FFFFFF40'}
keyboardType='numeric'
maxLength={4}
textInputStyles={{fontSize: 20}}
style={[styles.form_input]} />
{
this.state.minuteLeft > 0 || this.state.secondLeft > 0 ?
<Text style={[styles.fontPromtRegular, {color: 'white', marginTop: 30, fontSize: 17}]}>
งรห OTP ไดกครงใน {this.state.minuteLeft >= 10 ? this.state.minuteLeft : '0' + this.state.minuteLeft}:
{this.state.secondLeft >= 10 ? this.state.secondLeft : '0' + this.state.secondLeft} นาท
</Text>
:
<TouchableOpacity style={{marginTop: 30}} onPress={this.resentRequestOTP}>
<Text style={[styles.fontPromtRegular, {color: 'white', fontSize: 17}]}>ขอรหสอกคร</Text>
</TouchableOpacity>
}
</View>
<View style={{flex: 0.3, marginTop: 20}}>
<TouchableOpacity onPress={this.submitVerifyOTP}
disabled={this.state.otp === null || this.state.otp === ''}
style={styles.btnSubmit}>
<Text style={styles.textBtnSubmit}>
{t('confirm')}
</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</BackgroundImage>
<IndicatorLoading loadingVisible={this.state.is_loading}/>
</LinearGradient>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 40
},
fontPromtBold: {
fontFamily: 'Prompt-Bold'
},
fontPromtRegular: {
fontFamily: 'Prompt-Regular'
},
form_input: {
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'white',
borderRadius: 30,
borderWidth: 1,
width: '50%'
},
btnSubmit: {
marginTop: 35,
backgroundColor: 'white',
borderRadius: 30,
paddingVertical: 10,
paddingHorizontal: 50,
},
textBtnSubmit: {
color: '#2470A1',
fontFamily: 'Prompt-Bold',
fontSize: 16,
textAlign: 'center'
}
})
export default VerifyOTP

View File

@ -1,20 +1,21 @@
import React, { Component } from 'react'
import React, {Component, useCallback} from 'react';
import { TouchableOpacity, View, Alert, ScrollView, SafeAreaView, KeyboardAvoidingView, Platform } from 'react-native'
import Image from 'react-native-fast-image'
import GetWidthHeightDevice from '../../components/GetWidthHeightDevice'
import { CustomButton } from '../../components/CustomButton'
import { CustomInput } from '../../components/CustomInput'
import { login } from '../../api/UserApi'
import {login, payment} from '../../api/UserApi'
import { setToken } from '../../api/api'
import { BackgroundImage } from '../../components/BackgroundImage'
import LinearGradient from 'react-native-linear-gradient'
import Text from '../../components/Text'
import { bindActionCreators } from 'redux'
import { appSetDevice, appSetPushToken, appSetToken, appSetUser } from '../../redux/app/action'
import {appSetDevice, appSetPushToken, appSetToken, appSetUser} from '../../redux/app/action'
import {connect} from 'react-redux'
import IndicatorLoading from '../../components/IndicatorLoading';
import { locale, t } from '../../utils/i18n'
import moment from "moment";
import messaging from "@react-native-firebase/messaging";
class LoginScreen extends Component {
@ -22,35 +23,64 @@ class LoginScreen extends Component {
super(props)
this.state = {
isLoading: false,
username: null,
password: null,
username: '0935697758',
password: '123456',
payment: [],
sum_payment: [],
all_payment : [],
room_number_array : [],
}
this._login = this._login.bind(this)
}
_login() {
async _login () {
if (this.state.username && this.state.password) {
var regex = /^\d+$/;
if (regex.test(this.state.username) === true) {
let params = {
mobile: this.state.username,
password: this.state.password
console.log('true')
const fcm = messaging()
if (!await fcm.hasPermission()) {
try {
await messaging().requestPermission()
} catch (error) {
}
}
const fcmToken = await messaging().getAPNSToken();
let params = {
// mobile: this.state.username,
username: this.state.username,
password: this.state.password,
fcm_token: fcmToken
}
console.log('params >> ', params)
console.log('fcmToken >>>>>>>>>>>>>>>>>>>>>>>>> ', fcmToken)
this.setState({isLoading:true})
login(params)
.then((res) => {
if (res.ok) {
if (res.data.token) {
setToken(res.data.token)
this.props.appSetToken(res.data.token)
this.props.appSetUser(res.data.user)
setTimeout(() => {
this.setState({isLoading:false},() => {
console.log('data >>>>> ', res.data)
if (res.data.access_token) {
// setToken(res.data.token)
// this.props.appSetToken(res.data.token)
setToken(res.data.access_token)
this.props.appSetToken(res.data.access_token)
this.props.navigation.navigate('HomeScreen',{isLogin:true})
})
}, 300);
let user_data = res.data.user;
this.props.appSetUser(user_data)
setTimeout(() => {
console.log('tokennnnnnnnnnnnnn >>>>>>>>>>>> ', this.props.token)
console.log('userrrrrrrrrrrrrrr >>>>>>>>>>>> ', this.props.user)
}, 5000)
}else {
setTimeout(() => {
Alert.alert(null, 'ท่านกรอก บัญชีผู้ใช้งาน หรือ รหัสผ่านผิด')
}, 600);
}
} else {
setTimeout(() => {
@ -65,7 +95,7 @@ class LoginScreen extends Component {
} else {
Alert.alert(null, 'กรุณากรอกข้อมูลให้ครบถ้วน')
}
}
};
render() {
return (
@ -137,6 +167,11 @@ class LoginScreen extends Component {
}}
style={styles.form_input} />
</View>
<View style={{flex: 1, marginBottom: 10}}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('ForgetPassword')}>
<Text style={{color: '#FFF', fontSize: 15, textAlign: 'right'}}>{t('forget_password')}?</Text>
</TouchableOpacity>
</View>
<View style={[styles.row, { marginTop: 15 }]}>
<CustomButton
colorText={'#2470A1'}
@ -149,14 +184,14 @@ class LoginScreen extends Component {
//onPress={() => { this.props.navigation.navigate('HomeScreen') }}
/>
</View>
<View style={{marginTop:10}}>
{/* <View style={{marginTop:10}}>
<View style={[styles.row, { flex: 1, flexDirection: locale() == 'my' ? 'column' : 'row', alignItems: 'center', textAlign: 'center', justifyContent: 'center' }]}>
<Text style={{ color: '#FFF', fontSize: 15,/* fontFamily: 'Prompt-Regular', */ }}> {t('not_a_member')} </Text>
<Text style={{ color: '#FFF', fontSize: 15}}> {t('not_a_member')} </Text>
<TouchableOpacity onPress={() => { this.props.navigation.navigate('Register') }}>
<Text style={{ color: '#FFF', fontSize: 15, fontFamily: 'Prompt-Bold' }}> {t('create_account')} </Text>
</TouchableOpacity>
</View>
</View>
</View> */}
</View>
</View>
</ScrollView>

View File

@ -26,15 +26,24 @@ class RegisterScreen extends Component {
_onNextStep = async () => {
var regex = /^\d+$/;
if (this.state.user.mobile && this.state.user.password && this.state.user.password == this.state.user.password_confirm) {
if (regex.test(this.state.user.mobile) === true) {
console.log('mobile ===> ', this.state.user)
if (this.state.user.mobile && this.state.user.password && this.state.user.password && this.state.user.password_confirm) {
if (regex.test(this.state.user.mobile) === false) {
Alert.alert(null, 'ท่านกรอกรูปแบบโทรศัพท์ไม่ถูกต้อง')
} else if (this.state.user.password !== this.state.user.password_confirm){
Alert.alert(null, 'รหัสผ่านไม่ตรงกัน')
} else {
this.props.appSetUser(this.state.user)
this.props.navigation.navigate('RegisterFormLogin');
} else {
Alert.alert(null, 'ท่านกรอกรูปแบบโทรศัพท์ไม่ถูกต้อง')
}
} else {
Alert.alert(null, 'รหัสผ่านไม่ตรงกัน')
if(!this.state.user.mobile){
Alert.alert(null, 'กรุณากรอกเบอร์โทรศัพท์')
} else if(!this.state.user.password){
Alert.alert(null, 'กรุณากรอกรหัสผ่าน')
} else if(!this.state.user.password_confirm){
Alert.alert(null, 'กรุณากรอกยืนยันรหัสผ่าน')
}
}
}

View File

@ -1,23 +1,23 @@
import React, { Component } from 'react'
import { Alert, ScrollView, TouchableOpacity, View, Platform, KeyboardAvoidingView } from 'react-native'
import React, {Component} from 'react'
import {Alert, ScrollView, TouchableOpacity, View, Platform, KeyboardAvoidingView} from 'react-native'
import Image from 'react-native-fast-image'
import { CustomStepIndicator } from '../../components/StepIndicator'
import { CustomInput } from '../../components/CustomInput'
import { CustomButton } from '../../components/CustomButton'
import {CustomStepIndicator} from '../../components/StepIndicator'
import {CustomInput} from '../../components/CustomInput'
import {CustomButton} from '../../components/CustomButton'
import Icon from 'src/components/Icon'
import { bindActionCreators } from 'redux'
import { appSetUser } from '../../redux/app/action'
import { connect } from 'react-redux'
import { Picker } from 'native-base'
import {bindActionCreators} from 'redux'
import {appSetUser} from '../../redux/app/action'
import {connect} from 'react-redux'
import DropDownPicker from 'react-native-dropdown-picker'
import moment from 'moment'
import { BackgroundImage_RegisterForm } from '../../components/BackgroundImage_RegisterForm'
import {BackgroundImage_RegisterForm} from '../../components/BackgroundImage_RegisterForm'
import LinearGradient from 'react-native-linear-gradient'
import Text from '../../components/Text'
import { getBuildingByProjectId, project } from '../../api/UserApi'
import {getBuildingByProjectId, project} from '../../api/UserApi'
import ImagePicker from 'react-native-image-crop-picker'
import ActionSheet from 'react-native-action-sheet'
import CustomDatePicker from '../room/CustomDatePicker';
import { t } from '../../utils/i18n'
import {t} from '../../utils/i18n'
let ACTIONSHEET_BUTTONS = [
'ถ่ายรูป',
@ -27,6 +27,39 @@ let ACTIONSHEET_BUTTONS = [
let CANCEL_INDEX = 2
const DropdownSelection = (props) => {
return (
<View>
<DropDownPicker
style={{
borderColor: '1px solid rgba(0, 0, 0, 0.25)',
backgroundColor: 'transparent',
borderColor: 'transparent',
marginTop: -6,
}}
placeholderStyle={{
color: "#FFFFFF40"
}}
dropDownContainerStyle={{
borderColor: '1px solid rgba(0, 0, 0, 0.25)',
fontFamily: 'Prompt-Regular'
}}
textStyle={{
color: 'white',
fontFamily: 'Prompt-Regular',
fontSize: 14
}}
translation={{
NOTHING_TO_SHOW: "ไม่มีรายการข้อมูล"
}}
listMode='MODAL'
showArrowIcon={false}
{...props}
/>
</View>
)
}
class RegisterFormLoginScreen extends Component {
constructor(props) {
super(props)
@ -35,12 +68,16 @@ class RegisterFormLoginScreen extends Component {
project_list: [],
building_list: [],
selected_project: 0,
project_name:t('choose_project'),
project_name: t('choose_project'),
image_url: require('../../../assets/images/profile.png'),
enableSummit: false,
checkFullname: false,
checkCitizenID: false,
checkBirthDate: null
checkBirthDate: null,
checkRoomNo: false,
is_customer: true,
openProject: false,
openBuilding: false
}
this._onNextStep = this._onNextStep.bind()
this.onImagePick = this.onImagePick.bind(this)
@ -52,7 +89,7 @@ class RegisterFormLoginScreen extends Component {
this.setDefaultUserData()
}
setDefaultUserData(){
setDefaultUserData() {
this.setState({
user: {
...this.state.user,
@ -65,9 +102,21 @@ class RegisterFormLoginScreen extends Component {
project()
.then(res => {
if (res.ok) {
return this.setState({
project_list: res.data.data,
selected_project: res.data.data[0].id
console.log('data >>> ', res.data)
let project_list = res.data.data.map((data) => {
return {
...data,
value: data.id,
label: this.props.lang === 'th' ? data.name_th : data.name_en,
labelStyle: {
color: 'black'
}
}
})
this.setState({
project_list,
// selected_project: res.data.data[0].id
})
}
})
@ -81,11 +130,21 @@ class RegisterFormLoginScreen extends Component {
.then(res => {
// console.log('-------------------> ', res)
if (res.ok) {
let building_list = res.data.data.map((data) => {
return {
...data,
value: data.room_build,
label: data.room_build,
labelStyle: {
color: 'black'
}
}
})
this.setState({
building_list: res.data.data,
building_list,
user: { //set default building index 0
...this.state.user,
building: res.data.data[0].room_build
// building: res.data.data[0].room_build
}
})
}
@ -94,7 +153,14 @@ class RegisterFormLoginScreen extends Component {
_onNextStep = async () => {
// if (this.state.user.email && this.state.user.mobile) {
if (this.state.user.mobile && this.state.user.tax_id && this.state.user.name && this.state.user.birth_date) {
// let tax_id = this.state.user && this.state.user.tax_id
// if(!tax_id && !this.state.is_customer){
// tax_id = (Math.floor(1000000000000 + Math.random() * 9000000000000)).toString();
// }
if (this.state.user.mobile
// && this.state.is_customer && this.state.user.tax_id && (this.state.user.tax_id.toString()).length > 0
// && tax_id.length > 0
&& this.state.user.name) {
/*var email_validate = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
if (email_validate.test(this.state.user.email) === true) {
this.props.appSetUser(this.state.user)
@ -102,16 +168,26 @@ class RegisterFormLoginScreen extends Component {
} else {
Alert.alert(null, 'ท่านกรอกรูปแบบอีเมลไม่ถูกต้อง')
}*/
console.log('check user data next <<<<<<<< ',this.state.user);
console.log('check user data next <<<<<<<< ', this.state.user);
this.setState({
user: {
...this.state.user,
// tax_id: !this.state.is_customer ? Math.floor(1000000000000 + Math.random() * 9000000000000) : this.state.user.tax_id,
// is_customer: this.state.is_customer
}
}, () => {
// console.log('user >>> ', this.state.user)
this.props.appSetUser(this.state.user)
// next page !!
this.props.navigation.navigate('RegisterProfile')
this.props.navigation.navigate('RegisterProfile', {image_url: this.state.image_url})
})
} else {
console.log('กรุณากรอกข้อมูลให้ครบถ้วน')
Alert.alert(null, 'กรุณากรอกข้อมูลให้ครบถ้วน')
}
}
onImagePick () {
onImagePick() {
ImagePicker.openPicker({
width: 300,
height: 300,
@ -125,7 +201,7 @@ class RegisterFormLoginScreen extends Component {
name: 'image_profile.jpg',
}
this.setState({
image_url: { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height },
image_url: {uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height},
images: null,
user: {
...this.state.user,
@ -135,7 +211,7 @@ class RegisterFormLoginScreen extends Component {
}).catch(e => alert(e))
}
onTakeCamera () {
onTakeCamera() {
ImagePicker.openCamera({
cropping: true,
width: 300,
@ -149,7 +225,7 @@ class RegisterFormLoginScreen extends Component {
name: 'image_profile.jpg',
}
this.setState({
image_url: { uri: image.path, width: image.width, height: image.height, mime: image.mime },
image_url: {uri: image.path, width: image.width, height: image.height, mime: image.mime},
images: null,
user: {
...this.state.user,
@ -159,27 +235,49 @@ class RegisterFormLoginScreen extends Component {
}).catch(e => alert(e))
}
handleRequired = (e,type) => {
validateNextStepBtn(){
if (this.state.checkFullname.length > 0 && this.state.user.project && this.state.user.building && this.state.checkRoomNo.length > 0) {
this.setState({
enableSummit: true
});
} else {
this.setState({
enableSummit: false
});
}
}
handleRequired = (e, type) => {
// e = value
console.log(type + " : ", e);
switch(type) {
switch (type) {
case 'fullname':
// code block
this.setState(() => ({ ['checkFullname']: e }));
this.setState(() => ({['checkFullname']: e}), () => {
this.validateNextStepBtn()
});
break;
case 'citizen_id':
this.setState(() => ({ ['checkCitizenID']: e }));
case 'room':
// code block
this.setState(() => ({['checkRoomNo']: e}), () => {
this.validateNextStepBtn()
});
break;
/*case 'citizen_id':
this.setState(() => ({['checkCitizenID']: e}));
break;*/
default:
this.validateNextStepBtn()
// code block
}
// console.log(this.state.user.birth_date);
// check all
if(this.state.checkFullname.length >= 1 && this.state.checkCitizenID.length >= 1 && typeof this.state.user.birth_date != 'undefined'){
this.setState(() => ({ ['enableSummit']: true }));
}
setOpen = (open, key) => {
this.setState({
[key]: open
})
}
render() {
@ -193,9 +291,9 @@ class RegisterFormLoginScreen extends Component {
resizeMode: 'cover'
}}
>
<KeyboardAvoidingView style={{flex:1}} keyboardVerticalOffset={Platform.OS == 'ios' ? 75 : 0} behavior={Platform.OS == 'ios' ? "padding" : ""} enabled>
<KeyboardAvoidingView style={{flex: 1}} keyboardVerticalOffset={Platform.OS == 'ios' ? 75 : 0} behavior={Platform.OS == 'ios' ? "padding" : ""} enabled>
<BackgroundImage_RegisterForm>
<ScrollView showsVerticalScrollIndicator={false} style={{ flex: 1 }}>
<ScrollView showsVerticalScrollIndicator={false} style={{flex: 1}}>
<View style={styles.container}>
<View style={[styles.step_indicator]}>
<CustomStepIndicator
@ -206,6 +304,7 @@ class RegisterFormLoginScreen extends Component {
<View style={styles.logo}>
<View
style={{
flex: 1,
flexGrow: 1,
backgroundColor: '#3AA40C',
alignItems: 'center',
@ -261,7 +360,7 @@ class RegisterFormLoginScreen extends Component {
</View>
{/*<Text> LOGO </Text>*/}
</View>
<View style={{ flex: 1 }}>
<View style={{flex: 1}}>
<View style={[styles.form]}>
<Text style={styles.headerTitle}> {t('profile')} </Text>
<View style={styles.row}>
@ -281,7 +380,17 @@ class RegisterFormLoginScreen extends Component {
}
})
}}
onChangeText={(evt) => this.handleRequired(evt, "fullname")}
value={this.state.user.name}
onChangeText={(evt) => {
this.handleRequired(evt, "fullname")
this.setState({
user:{
...this.state.user,
name: evt.replace(/\u0020/, '\u00a0')
}
})
}}
placeholder={t('specific_fullname')}
placeholderTextColor={'#FFFFFF40'}
/>
@ -309,7 +418,7 @@ class RegisterFormLoginScreen extends Component {
placeholderTextColor={'#FFFFFF40'}
/>
</View> */}
<View style={styles.row}>
{/*<View style={styles.row}>
<View style={styles.row_grow_first}>
<View
style={{
@ -359,9 +468,9 @@ class RegisterFormLoginScreen extends Component {
</View>
</View>
</View>
</View>
</View>*/}
{/* /// */}
<View style={styles.row}>
{/*<View style={styles.row}>
<View style={styles.row_grow}>
<CustomDatePicker titleText={t('birth_date')} dateText={this.state.user.text_birth} maxDate={new Date()} handleDate={(data) => {
this.setState({
@ -371,32 +480,12 @@ class RegisterFormLoginScreen extends Component {
birth_date_show: moment(data).format('MM/DD/YYYY'),
text_birth: moment(data).add(543, 'years').format('DD-MM-YYYY')
}
})
}, () => {
this.handleRequired(data, "birth_date");
})
}}/>
</View>
</View>
<View style={styles.row}>
<CustomInput
maxLength={13}
style={styles.register_input}
labelColor={'white'}
placeholderTextColor={'white'}
labelName={t('citizen_id')}
onEndEditing={e => {
let input = e.nativeEvent.text
this.setState({
user: {
...this.state.user,
tax_id: input
}
})
}}
onChangeText={(evt) => this.handleRequired(evt, "citizen_id")}
placeholder={t('citizen_id_13')}
placeholderTextColor={'#FFFFFF40'}
/>
</View>
</View>*/}
<View style={styles.row}>
<CustomInput
maxLength={10}
@ -420,6 +509,74 @@ class RegisterFormLoginScreen extends Component {
value={this.state.user.mobile || ''}
/>
</View>
{/*<View style={styles.userTypeContainer}>
<TouchableOpacity style={styles.radioInput}
onPress={() => {this.setState({
is_customer: true }, () => {
this.handleRequired(this.state.is_customer, "user_type");
})
}}
>
{
this.state.is_customer ?
<Image source={require('../../../assets/images/radio_button_checked.png')} style={{width: 20, height: 20, marginRight: 5}} />
: <Image source={require('../../../assets/images/radio_button.png')} style={{width: 20, height: 20, marginRight: 5}} />
}
<Text style={{color: 'white'}}>{t('customer')}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.radioInput}
onPress={() => {
this.setState({
is_customer: false,
user: {
...this.state.user,
tax_id: '',
building: '',
room: ''
},
checkCitizenID: false
}, () => {
this.handleRequired(this.state.is_customer, "user_type");
})
}}
>
{
this.state.is_customer ?
<Image source={require('../../../assets/images/radio_button.png')} style={{width: 20, height: 20, marginRight: 5}} />
: <Image source={require('../../../assets/images/radio_button_checked.png')} style={{width: 20, height: 20, marginRight: 5}} />
}
<Text style={{color: 'white'}}>{t('guest')}</Text>
</TouchableOpacity>
</View>*/}
{/*{
this.state.is_customer &&
<View style={styles.row}>
<CustomInput
maxLength={13}
style={styles.register_input}
labelColor={'white'}
placeholderTextColor={'white'}
labelName={t('citizen_id')}
onEndEditing={e => {
let input = e.nativeEvent.text
this.setState({
user: {
...this.state.user,
tax_id: input
}
})
}}
onChangeText={(evt) => this.handleRequired(evt, "citizen_id")}
placeholder={t('citizen_id_13')}
placeholderTextColor={'#FFFFFF40'}
/>
</View>
}*/}
<Text style={styles.headerTitle}> {t('accom_info')} </Text>
<View style={styles.row}>
<View
@ -448,43 +605,36 @@ class RegisterFormLoginScreen extends Component {
{t('project')}
</Text>
</View>
<View style={{ flex: 1 }}>
<Picker
// mode="dropdown"
style={{
height: 40,
color:'white'
}}
textStyle={{color:'white',fontFamily:'Prompt-Regular',fontSize:14}}
labelName={t('project')}
<View style={{flex: 1}}>
<DropdownSelection
open={this.state.openProject}
items={this.state.project_list}
value={this.state.selected_project}
setOpen={(open) => this.setOpen(open, 'openProject')}
placeholder={t('choose_project')}
placeholderStyle={{color:'#FFFFFF40'}}
selectedValue={this.state.project_item}
onValueChange={e => {
// console.log('@@@@@@ project selected --------> ',e);
onSelectItem={(e) => {
this.setState({
project_name: e.name,
project_name: e.label,
project_item: e,
selected_project: e.id,
user: {
...this.state.user,
project: e.code,
project_name : e.name
project_name: this.props.lang === 'th' ? e.name_th : e.name_en
},
}, () => {
// console.log('check project selected --------> ',this.state.project_name);
console.log('check project selected --------> ',this.state.project_name);
this.handleRequired(e, "project")
this.getBuildingList()
})
}}
>
{this.state.project_list.map((item) => {
return <Picker.Item label={item.name} value={item} key={'project_'+item}/>
})}
</Picker>
/>
</View>
</View>
</View>
{
this.state.is_customer &&
<View style={styles.row}>
<View
style={{
@ -514,31 +664,25 @@ class RegisterFormLoginScreen extends Component {
{t('building')}
</Text>
</View>
<View style={{ flex: 1 }}>
<Picker
// mode="dropdown"
style={{
height: 40,
color:'white'
}}
textStyle={{color:'white',fontFamily:'Prompt-Regular',fontSize:14}}
labelName={t('building')}
placeholder={'เลือกอาคาร'}
placeholderStyle={{color:'#FFFFFF40'}}
selectedValue={this.state.user.building}
onValueChange={e => {
<View style={{flex: 1}}>
<DropdownSelection
open={this.state.openBuilding}
items={this.state.building_list}
value={this.state.user && this.state.user.building}
setOpen={(open) => this.setOpen(open, 'openBuilding')}
placeholder='เลือกอาคาร'
onSelectItem={(e) => {
console.log('e >>>>>> ', e)
this.setState({
user: {
...this.state.user,
building: e
building: e.value
}
}, () => {
this.handleRequired(e, "building")
})
}}
>
{this.state.building_list.map((item) => {
return <Picker.Item label={item.room_build} value={item.room_build} key={'building_'+item.room_build}/>
})}
</Picker>
/>
</View>
</View>
<View style={styles.row_grow}>
@ -549,13 +693,15 @@ class RegisterFormLoginScreen extends Component {
placeholderTextColor={'white'}
//New Code style
labelName={t('room2')}
onEndEditing={e => {
let input = e.nativeEvent.text
onChangeText={e => {
// let input = e.nativeEvent.text
this.setState({
user: {
...this.state.user,
room: input
room: e
}
}, () => {
this.handleRequired(e, "room")
})
}}
placeholder={t('room_no')}
@ -563,11 +709,25 @@ class RegisterFormLoginScreen extends Component {
/>
</View>
</View>
<View style={styles.buttons}>
}
<View style={[styles.buttons, {display: this.state.enableSummit ? 'none' : 'flex'}]}>
<View style={styles.row_grow}>
<CustomButton
// disabled="true"
style={ this.state.enableSummit ? [styles.btn_next_register , styles.enableNext]: [styles.btn_next_register , styles.disableNext] } // enableNext
style={styles.disableNext} // enableNext
title={t('next')}
sizeText={14}
// onPress={this._onNextStep}
/>
</View>
</View>
<View style={[styles.buttons, {display: this.state.enableSummit ? 'flex' : 'none'}]}>
<View style={styles.row_grow}>
<CustomButton
// disabled="true"
style={styles.enableNext} // enableNext
title={t('next')}
sizeText={14}
onPress={this._onNextStep}
@ -592,6 +752,7 @@ const styles = {
flexDirection: 'column'
},
logo: {
flex: 1,
backgroundColor: '#3AA40C',
height: '20%',
flexDirection: 'row',
@ -613,7 +774,8 @@ const styles = {
paddingBottom: 0
},
step_indicator: {
backgroundColor: '#3AA40C'
backgroundColor: '#3AA40C',
flex: 1
},
buttons: {
flexDirection: 'row',
@ -642,22 +804,50 @@ const styles = {
fontFamily: 'Prompt-Regular',
borderRadius: 30
},
disableNext :{
disableNext: {
opacity: 0.65,
cursor: "not-allowed",
backgroundColor: '#AAAAAA'
},
enableNext :{
enableNext: {
opacity: 1,
color: '#FFFFFF',
backgroundColor: '#145EB3'
}
},
userTypeContainer: {
flex: 1,
flexDirection: 'row',
paddingTop: 5,
paddingBottom: 10
},
radioInput: {
flex: 1,
flexDirection: 'row',
alignItems: 'center'
},
custom_button_container: {
// flex:1,
// flexDirection: 'row',
height: 35,
abckgroundColor: '#FF9500',
borderRadius: 5,
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
icon: {
justifyContent: 'center',
// alignItems: '',
// flex: 1,
paddingLeft: 5,
paddingRight: 5
},
}
const mapDisPatchToProps = state => {
return state.app
}
const setUser = dispatch => bindActionCreators({ appSetUser }, dispatch)
const setUser = dispatch => bindActionCreators({appSetUser}, dispatch)
export default connect(
mapDisPatchToProps,
setUser

View File

@ -5,14 +5,15 @@ import { CustomStepIndicator } from '../../components/StepIndicator'
import GetWidthHeightDevice from '../../components/GetWidthHeightDevice'
import { CustomButton } from '../../components/CustomButton'
import { connect } from 'react-redux'
import { register, registerDevice, testConnect } from '../../api/UserApi'
import {checkPaymentMeter, register, registerDevice, testConnect} from '../../api/UserApi'
import { bindActionCreators } from 'redux'
import { appSetDevice, appSetPushToken, appSetToken, appSetUser } from '../../redux/app/action'
import firebase, { Notification } from 'react-native-firebase'
import {appSetDevice, appSetPushToken, appSetToken, appSetUser, setPopupNotification} from '../../redux/app/action'
import messaging from "@react-native-firebase/messaging";
import moment from 'moment'
import { setToken } from '../../api/api'
import { BackgroundImage_RegisterForm } from '../../components/BackgroundImage_RegisterForm'
import LinearGradient from 'react-native-linear-gradient';
import DeviceInfo from 'react-native-device-info';
import Text from '../../components/Text';
import { t } from '../../utils/i18n'
@ -23,7 +24,8 @@ class RegisterProfileScreen extends Component {
this.state = {
auth: false,
disableButton: false
disableButton: false,
image_url: require('../../../assets/images/profile.png'),
}
this._register = this._register.bind(this);
@ -36,27 +38,31 @@ class RegisterProfileScreen extends Component {
if (!this.props.push_token) {
this.initNotification();
}
this.setState({
image_url: this.props.navigation.getParam('image_url', require('../../../assets/images/profile.png'))
})
}
initNotification = async () => {
await this.setPermission()
const fcmToken = await firebase.messaging().getToken()
const fcmToken = await messaging().getToken()
console.log('fcmToken', fcmToken)
if (fcmToken) {
this.props.appSetPushToken(fcmToken)
console.log('fcmToken', this.props)
} else {
Alert.alert(null, 'Cannot get push token.', [{ text: 'ok' }])
}
}
setPermission = async () => {
try {
const enabled = await firebase.messaging().hasPermission()
const enabled = await messaging().hasPermission()
if (!enabled) {
await firebase.messaging().requestPermission()
await messaging().requestPermission()
}
} catch (error) {
console.log('error', error)
@ -72,14 +78,22 @@ class RegisterProfileScreen extends Component {
this.props.appSetDevice(resultSendDevice.data.device)
}
}
if (!this.props.device || !this.props.push_token) {
let systemName = DeviceInfo.getSystemName();
let deviceId = null
if(systemName == "Android") {
if (!this.props.device) {
Alert.alert(null, 'Cannot get push token or device.', [{ text: 'ok' }])
return;
}
deviceId = this.props.device.id
}
register({
...this.props.user,
device_id: this.props.device.id
device_id: deviceId,
name: this.props.user.name.replace(/\u00a0/g, /\u0020/),
fcm_token: this.props.push_token
}).then(
(res) => {
if (res.ok && res.data.success) {
@ -89,8 +103,40 @@ class RegisterProfileScreen extends Component {
this.props.appSetUser(res.data.customer)
this.props.appSetToken(res.data.token)
setToken(token)
Alert.alert(null, t('register_success'), [{ text: t('ok') }])
this.props.navigation.navigate('HomeScreen')
Alert.alert(
'',
t('register_success'),
[
{ text: 'OK', onPress: () => {
/*checkPaymentMeter()
.then(result => {
if(result.data){
let data = {
pending_payment: result.data.pending_payment != null ? result.data.pending_payment : 0,
is_notified_electric: result.data.user.is_notified_electric,
is_notified_overdue: result.data.user.is_notified_overdue,
is_notified_meter: result.data.user.is_notified_meter,
payment_id: result.data.payment_id,
notified_meter_at: result.data.notified_meter_at ? result.data.notified_meter_at : moment().format('DD MMM YYYY')
}
this.props.setPopupNotification(data)
}
})*/
this.setState({isLoading:false},() => {
this.props.navigation.navigate('HomeScreen',{isLogin:true})
})
}
}
],
{ cancelable: false }
)
//Alert.alert(null, t('register_success'), [{ text: t('ok') }])
//this.props.navigation.navigate('HomeScreen')
}
} else {
this.props.appSetUser(null)
@ -125,7 +171,7 @@ class RegisterProfileScreen extends Component {
}}>
<Image
style={{ width: 100, height: 100, borderRadius: 50, borderColor: 'white', borderWidth: 2 }}
source={require('../../../assets/images/profile.png')}
source={this.state.image_url}
/>
</View>
{/*<Text> LOGO </Text>*/}
@ -138,10 +184,10 @@ class RegisterProfileScreen extends Component {
<View style={[styles.table]}>
<View style={styles.row_title}>
<Text style={styles.title_data}> </Text>
<Text style={styles.title_data}> {t('name')} </Text>
{/* <Text style={styles.title_data}> อีเมล </Text> */}
<Text style={styles.title_data}> {t('gender')} </Text>
<Text style={styles.title_data}> {t('birth_date')} </Text>
{/*<Text style={styles.title_data}> {t('gender')} </Text>*/}
{/*<Text style={styles.title_data}> {t('birth_date')} </Text>*/}
<Text style={styles.title_data}> {t('phone2')} </Text>
</View>
{
@ -149,8 +195,8 @@ class RegisterProfileScreen extends Component {
<View style={styles.row_data}>
<Text style={styles.detail_data}> {user.name} </Text>
{/* <Text style={styles.detail_data}> {user.email} </Text> */}
<Text style={styles.detail_data}> {user.gender} </Text>
<Text style={styles.detail_data}> {moment(user.birth_date_show).add(543, 'years').format('D MMMM YYYY')} </Text>
{/*<Text style={styles.detail_data}> {user.gender} </Text>*/}
{/*<Text style={styles.detail_data}> {moment(user.birth_date_show).add(543, 'years').format('D MMMM YYYY')} </Text>*/}
<Text style={styles.detail_data}> {user.mobile} </Text>
</View>
}
@ -276,5 +322,5 @@ const styles = {
const mapDisPatchToProps = state => {
return state.app
}
const setUser = dispatch => bindActionCreators({ appSetToken, appSetPushToken, appSetDevice, appSetUser }, dispatch)
const setUser = dispatch => bindActionCreators({ appSetToken, appSetPushToken, appSetDevice, appSetUser, setPopupNotification }, dispatch)
export default connect(mapDisPatchToProps, setUser)(RegisterProfileScreen)

View File

@ -4,14 +4,25 @@ import Text from '../../components/Text';
import { Badge } from 'native-base'
import { WebView } from 'react-native-webview';
import { t } from '../../utils/i18n'
import {connect} from "react-redux";
import {bindActionCreators} from "redux";
import {appCleanUser} from "../../redux/app/action";
import I18n from "i18n-js";
export default class TermsAndCondition extends Component {
class TermsAndCondition extends Component {
constructor(props) {
super(props);
this.state = {
currentLocale: 'th'
};
}
componentDidMount(): void {
this.setState({
currentLocale : I18n.currentLocale()
})
}
render() {
return (
<ScrollView contentContainerStyle={{flex:1}}>
@ -26,7 +37,8 @@ export default class TermsAndCondition extends Component {
flex: 1,
}}
originWhitelist={['*']}
source={{ uri: 'https://www.csasset.co.th/Privacy-Policy-TH.htm'}}
// source={ this.state.currentLocale === 'th' ? { uri: 'https://power-condo-dev.testsiteth.xyz/privacy-policy-new'} : {uri: 'https://power-condo-dev.testsiteth.xyz/privacy-policy-en'}}
source={ this.state.currentLocale === 'th' ? { uri: 'https://powercondo.csasset.co.th/privacy-policy-new'} : {uri: 'https://powercondo.csasset.co.th/privacy-policy-en'}}
javaScriptEnabled={true}
domStorageEnabled={true}
onNavigationStateChange={(event) => {
@ -41,6 +53,7 @@ export default class TermsAndCondition extends Component {
</View>
<View style={{flexDirection:'row',justifyContent:'space-around',height:60}}>
<TouchableOpacity onPress={() => {
this.props. appCleanUser();
this.props.navigation.goBack()
}}>
<View>
@ -64,3 +77,6 @@ export default class TermsAndCondition extends Component {
);
}
}
const clearUser = dispatch => bindActionCreators({appCleanUser}, dispatch);
export default connect(null, clearUser)(TermsAndCondition);

View File

@ -32,6 +32,12 @@ export default class Meter extends Component {
this.getMeter = this.getMeter.bind(this)
}
componentWillUnmount() {
if(this.props && this.props.navigation && this.props.navigation.state && this.props.navigation.state.params && this.props.navigation.state.params.getNotification){
this.props.navigation.state.params.getNotification()
}
}
getMeter(){
this.setState({
isLoading: true
@ -71,7 +77,8 @@ export default class Meter extends Component {
cropping: true,
width: 300,
height: 100,
includeExif: true
includeExif: true,
includeBase64: true
}).then(image => {
console.log('received image', image)
let image_meter = {
@ -79,13 +86,15 @@ export default class Meter extends Component {
type: image.mime,
name: 'image_meter.jpg',
}
let image_data = { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height};
this.setState({
image_url: {uri: image.path, width: image.width, height: image.height, mime: image.mime},
image_url: image_data,
images: null,
image_preview: image_meter
}, () => {
this.selectedImage(this.state.image_url)
})
}).catch(e => alert(e))
}).catch(e => {})
}
selectedImage(image_meter){
@ -94,9 +103,9 @@ export default class Meter extends Component {
},() => {
console.log('selected image ',this.state.image_selected)
if(this.state.selected_type == 'pea'){
this.props.navigation.navigate('PEAMeter',{image: this.state.image_selected,room_id: this.state.room_list[this.state.room_snap_index].id})
this.props.navigation.navigate('PEAMeter',{image: this.state.image_selected, image_preview: this.state.image_preview, room_id: this.state.room_list[this.state.room_snap_index].id})
}else{
this.props.navigation.navigate('WaterMeter',{image: this.state.image_selected,room_id: this.state.room_list[this.state.room_snap_index].id})
this.props.navigation.navigate('WaterMeter',{image: this.state.image_selected, image_preview: this.state.image_preview, room_id: this.state.room_list[this.state.room_snap_index].id})
}
})
}
@ -104,7 +113,7 @@ export default class Meter extends Component {
_keyExtractor = (item, index) => 'meter_room_'+index;
_renderItem = ({item}) => (
<LinearGradient colors={['#4BAF3B', '#0E5E29']} style={{ height: 120, borderColor: 'white', borderRadius: 5, height: 120,paddingBottom:10, justifyContent:'space-between'}}>
<LinearGradient colors={['#4BAF3B', '#0E5E29']} style={{ borderColor: 'white', borderRadius: 5, height: 120,paddingBottom:10, justifyContent:'space-between'}}>
<View style={{ justifyContent: 'center',padding:16 }}>
<Text style={{ color: 'white', fontSize: 16 }}>{item.name}</Text>
<Text style={{ color: 'white', fontSize: 16 }}>{item.project_name}</Text>
@ -129,7 +138,7 @@ export default class Meter extends Component {
<View style={{paddingHorizontal:16,height: 96,backgroundColor:'white',borderWidth:1,borderColor:'#EAEAF4'}}>
<View style={{flex:1,flexDirection:'row'}}>
<View style={{height: 96,justifyContent:'center',marginRight:16}}>
<Image source={{uri:item.media.url}} style={{height: 64,width: 64,}} resizeMode={'contain'}/>
<Image source={{uri:item.image_meter}} style={{height: 64,width: 64,}} resizeMode={'contain'}/>
</View>
<View style={{flex:1,justifyContent:'center'}}>
<View style={styles.viewTextFlatlist}>

View File

@ -6,15 +6,18 @@ import PopupMeter from './PopupMeter';
import ImagePicker from 'react-native-image-crop-picker'
import {postMeter, postMeterImage} from '../../api/UserApi';
import moment from 'moment';
import { t } from '../../utils/i18n'
export default class PEAMeter extends Component {
constructor(props) {
super(props);
this.state = {
numberMeter: '0',
numberMeter: '',
isLoading: false,
isVisible: false,
image: this.props.navigation.getParam('image','no-image'),
image_send: {},
image_preview: this.props.navigation.getParam('image_preview', 'no-image'),
room_id: this.props.navigation.getParam('room_id','no-id'),
isConfirm: false
};
@ -24,22 +27,24 @@ export default class PEAMeter extends Component {
this.onOK = this.onOK.bind(this)
this.onPopup = this.onPopup.bind(this)
this.onTakeCamera = this.onTakeCamera.bind(this)
this.postImageToOCR = this.postImageToOCR.bind(this)
//this.postImageToOCR = this.postImageToOCR.bind(this)
}
componentDidMount = () => {
this.setState({
image_send: {
uri: this.state.image.uri,
type: this.state.image.mime,
name: `image_meter_${moment()}.jpg`,
// type: this.state.image.mime,
// name: `image_meter_${moment()}.jpg`,
width: this.state.image.width,
height: this.state.image.height
}
},() => {
this.postImageToOCR()
})
}/*,() => {
//this.postImageToOCR()
}*/)
};
postImageToOCR(){
/*postImageToOCR(){
let param = {
image: this.state.image_send
}
@ -52,7 +57,7 @@ export default class PEAMeter extends Component {
})
}
})
}
}*/
onTextChanged(text){
this.setState({
@ -75,7 +80,8 @@ export default class PEAMeter extends Component {
cropping: true,
width: 300,
height: 100,
includeExif: true
includeExif: true,
includeBase64: true
}).then(image => {
console.log('received image', image)
let image_meter = {
@ -83,18 +89,19 @@ export default class PEAMeter extends Component {
type: image.mime,
name: 'image_meter.jpg',
}
let image_data = { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height };
this.setState({
image_url: {uri: image.path, width: image.width, height: image.height, mime: image.mime},
images: null,
}, () => {
this.setState({
image: this.state.image_url,
image_send: image_meter
},() => {
image_send: image_data
}/*,() => {
this.postImageToOCR()
}*/)
})
})
}).catch(e => Alert.alert('Error',e))
}).catch(e => {})
}
onConfirm(){
@ -102,6 +109,11 @@ export default class PEAMeter extends Component {
}
onOK(){
if (!this.state.isLoading) {
this.setState({
isLoading: true,
isVisible: false
}, () => {
let param = {
room_id: this.state.room_id,
type: 'ค่าไฟ',
@ -113,9 +125,36 @@ export default class PEAMeter extends Component {
postMeter(param)
.then(res => {
console.log('response post meter ------> ',res.data)
this.onPopup()
if(res.data.success) {
console.log('success >>>>>> ')
Alert.alert(t('save_success'), '', [
{
text: t('ok'),
onPress: () => {
// this.setState({ isLoading: false })
this.props.navigation.goBack()
}
}
])
} else {
console.log('unsuccess >>>>>>')
Alert.alert(t('save_fail_and_try'), res.data.message ? res.data.message : '', [
{
text: 'ok',
onPress: () => {
// this.setState({
// isLoading: false,
// isVisible: false
// })
this.props.navigation.goBack()
}
}
], { cancelable: false })
}
})
.catch(err => this.setState({ isLoading: false }))
})
}
}
onPopup(){
@ -128,9 +167,9 @@ export default class PEAMeter extends Component {
return (
<ImageBackground source={require('../../../assets/images/tree2.png')} style={{flex:1,backgroundColor:'#EEFFD7',paddingTop:16}}>
<View style={{flex:1}}>
<SaveViewMeter amount={this.state.numberMeter} TypeName={'ไฟฟ้า'} TextChanged={this.onTextChanged} Confirm={this.onConfirm} ImageUri={this.state.image.uri} onTakeCamera={this.onTakeCamera} canConfirm={this.state.isConfirm}/>
<SaveViewMeter amount={this.state.numberMeter} TypeName={'ไฟฟ้า'} TextChanged={this.onTextChanged} Confirm={this.onConfirm} ImageUri={this.state.image_preview.uri} onTakeCamera={this.onTakeCamera} canConfirm={this.state.isConfirm}/>
</View>
<PopupMeter modalVisible={this.state.isVisible} onOk={this.onOK} onCancel={this.onPopup}/>
<PopupMeter modalVisible={this.state.isVisible} onOk={!this.state.isLoading ? this.onOK : null} onCancel={this.onPopup}/>
</ImageBackground>
);
}

View File

@ -26,7 +26,7 @@ export default class PopupMeter extends Component {
<TouchableOpacity style={{paddingHorizontal:15,}} onPress={() => {this.props.onCancel()}}>
<Text style={{color:'#00000040',fontSize: 14,}}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity style={{paddingHorizontal:15}} onPress={() => {this.props.onOk()}}>
<TouchableOpacity style={{paddingHorizontal:15}} onPress={() => {this.props.onOk && this.props.onOk()}}>
<Text style={{color:'#2C7C0B',fontSize: 14,}}>OK</Text>
</TouchableOpacity>
</View>

View File

@ -20,7 +20,7 @@ export default class SaveViewMeter extends Component {
<View style={{justifyContent:'center',alignItems:'center'}}>
<Image source={{uri:this.props.ImageUri}} resizeMode={'contain'} style={{borderRadius:5,height: 184,width:'100%'}}/>
</View>
<Text style={{color:'white',fontSize:14,textAlign:'center',marginVertical: 16,}}>ายเมอวนท {moment().format('DD/MM/YYYY HH:mm')} .</Text>
<Text style={{color:'black',fontSize:14,textAlign:'center',marginVertical: 16,}}>ายเมอวนท {moment().format('DD/MM/YYYY HH:mm')} .</Text>
<TouchableOpacity style={{height: 40,width: '100%',backgroundColor:'#007AFF',justifyContent:'center',alignItems:'center',borderRadius:5,flexDirection:'row'}}
onPress={this.props.onTakeCamera}>
<Icon nane={'ic_outline_camera'} size={22} color={'#FFFFFF'}/>

View File

@ -1,20 +1,23 @@
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { View, Text, Alert } from 'react-native';
import ImageBackground from 'react-native-fast-image'
import SaveViewMeter from './SaveViewMeter';
import PopupMeter from './PopupMeter';
import ImagePicker from 'react-native-image-crop-picker'
import {postMeter, postMeterImage} from '../../api/UserApi';
import moment from 'moment';
import {t} from "../../utils/i18n";
export default class WaterMeter extends Component {
constructor(props) {
super(props);
this.state = {
numberMeter: '0',
numberMeter: '',
isLoading: false,
isVisible: false,
image: this.props.navigation.getParam('image','no-image'),
image_send: {},
image_preview: this.props.navigation.getParam('image_preview', 'no-image'),
room_id: this.props.navigation.getParam('room_id','no-id'),
isConfirm: false
};
@ -24,22 +27,23 @@ export default class WaterMeter extends Component {
this.onOK = this.onOK.bind(this)
this.onPopup = this.onPopup.bind(this)
this.onTakeCamera = this.onTakeCamera.bind(this)
this.postImageToOCR = this.postImageToOCR.bind(this)
//this.postImageToOCR = this.postImageToOCR.bind(this)
}
componentDidMount = () => {
this.setState({
image_send: {
uri: this.state.image.uri,
type: this.state.image.mime,
name: `image_meter_${moment()}.jpg`,
width: this.state.image.width,
height: this.state.image.height
// name: `image_meter_${moment()}.jpg`,
}
},() => {
this.postImageToOCR()
})
}/*,() => {
//this.postImageToOCR()
}*/)
};
postImageToOCR(){
/*postImageToOCR(){
let param = {
image: this.state.image_send
}
@ -52,7 +56,7 @@ export default class WaterMeter extends Component {
})
}
})
}
}*/
onTextChanged(text){
this.setState({
@ -75,7 +79,8 @@ export default class WaterMeter extends Component {
cropping: true,
width: 300,
height: 100,
includeExif: true
includeExif: true,
includeBase64: true
}).then(image => {
console.log('received image', image)
let image_meter = {
@ -83,25 +88,32 @@ export default class WaterMeter extends Component {
type: image.mime,
name: 'image_meter.jpg',
}
let image_data = { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height };
this.setState({
image_url: {uri: image.path, width: image.width, height: image.height, mime: image.mime},
images: null,
}, () => {
this.setState({
image: this.state.image_url,
image_send: image_meter
},() => {
this.postImageToOCR()
image_send: image_data
}/*,() => {
//this.postImageToOCR()
}*/)
})
})
}).catch(e => Alert.alert('Error',e))
}).catch(e => {})
}
onConfirm(){
this.onPopup()
}
onOK(){
onOK() {
if (!this.state.isLoading) {
this.setState({
isLoading: true,
isVisible: false
}, () => {
let param = {
room_id: this.state.room_id,
type: 'ค่าน้ำ',
@ -113,10 +125,34 @@ export default class WaterMeter extends Component {
postMeter(param)
.then(res => {
console.log('response post meter ------> ',res.data)
this.onPopup()
if(res.data.success) {
Alert.alert(t('save_success'), '', [
{
text: t('ok'),
onPress: () => {
this.setState({ isLoading: false })
this.props.navigation.goBack()
}
}
])
} else {
Alert.alert(t('save_fail_and_try'), res.data.message ? res.data.message : '', [
{
text: 'ok',
onPress: () => {
this.setState({
isLoading: false,
isVisible: false
})
}
}
], { cancelable: false })
}
})
.catch(err => this.setState({ isLoading: false }))
})
}
}
onPopup(){
this.setState({
@ -128,9 +164,9 @@ export default class WaterMeter extends Component {
return (
<ImageBackground source={require('../../../assets/images/tree2.png')} style={{flex:1,backgroundColor:'#EEFFD7',paddingTop:16}}>
<View style={{flex:1,padding:16}}>
<SaveViewMeter amount={this.state.numberMeter} TypeName={'น้ำ'} TextChanged={this.onTextChanged} Confirm={this.onConfirm} ImageUri={this.state.image.uri} onTakeCamera={this.onTakeCamera} canConfirm={this.state.isConfirm}/>
<SaveViewMeter amount={this.state.numberMeter} TypeName={'น้ำ'} TextChanged={this.onTextChanged} Confirm={this.onConfirm} ImageUri={this.state.image_preview.uri} onTakeCamera={this.onTakeCamera} canConfirm={this.state.isConfirm}/>
</View>
<PopupMeter modalVisible={this.state.isVisible} onOk={this.onOK} onCancel={this.onPopup}/>
<PopupMeter modalVisible={this.state.isVisible} onOk={!this.state.isLoading ? this.onOK : null} onCancel={this.onPopup}/>
</ImageBackground>
);
}

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react'
import {
View, ScrollView, Dimensions, TouchableOpacity, StyleSheet, FlatList, RefreshControl, Animated, ActivityIndicator, Alert
View, ScrollView, Dimensions, TouchableOpacity, StyleSheet, FlatList, RefreshControl, Animated, ActivityIndicator, Platform, Alert, Modal
} from 'react-native'
import Image from 'react-native-fast-image'
import ImageBackground from 'react-native-fast-image'
@ -11,7 +11,7 @@ import LinearGradient from 'react-native-linear-gradient'
import { BackgroundImage } from '../../components/BackgroundImage'
import Text from '../../components/Text'
import { NavigationEvents } from 'react-navigation'
import { getNews, getNewsPage, getUserProfile, getNewsByProject, login } from '../../api/UserApi'
import {getNews, getNewsPage, getUserProfile, getNewsByProject, login, registerDevice, setPaymentLater, setFillInMeterLater, checkPaymentMeter} from '../../api/UserApi';
import { bindActionCreators } from 'redux'
import {
appSetDevice,
@ -27,13 +27,111 @@ import { connect } from 'react-redux'
import moment from 'moment'
import IndicatorLoading from '../../components/IndicatorLoading'
import { loginWithFacebook } from '../../components/FacebookUtils'
import { signinApple } from '../../components/AppleAuth'
import parseDateLocale from '../../utils/parseDateLocale'
import { from } from 'rxjs'
//import Slideshow from 'react-native-image-slider-show';
import appleAuth, {
AppleButton,
} from '@invertase/react-native-apple-authentication';
import { t, locale } from '../../utils/i18n'
import messaging from "@react-native-firebase/messaging";
import {store} from '../../redux/store';
const { height, width } = Dimensions.get('window')
console.disableYellowBox = true
function PopupNotiElectric({isVisible, onPress, onCancel, onPressLater, pending_payment, due_at_payment}) {
return <Modal visible={isVisible} transparent={true} animationType="none" key="popup-noti-electric">
<View style={styles.popupNotiContainer}>
<View style={styles.popupNoti}>
<View style={{width: '100%', alignItems: 'center'}}>
<Icon name='ic_shop_receive' color='#FF9500' size={70} style={{marginBottom: 10, width: '100%', textAlign: 'center'}}/>
<Text style={[{color: '#FF9500', marginBottom: 10, fontSize: 16}, styles.TextFont]}>ณมยอดคางชำระเง</Text>
<View style={styles.costText}>
<Text style={[{fontSize: 25, fontWeight: '500', textAlign: 'center'}, styles.TextFont]}>{pending_payment}</Text>
<Text style={[{color: '#8A8A8F', fontSize: 18, fontWeight: '400', position: 'absolute', right: 15, bottom: 8}, styles.TextFont]}>บาท</Text>
</View>
<Text style={[{color: '#FF9500', marginBottom: 10, textAlign: 'center' , fontSize: 14}, styles.TextFont]}>{t('please_pay_within')} {moment(due_at_payment).add('543', 'y').format('DD/MM/YYYY')}</Text>
<TouchableOpacity onPress={onPress} style={{width: '100%', marginTop: 10}}>
<Badge style={styles.badgeSubmit}>
<Text style={[{color: 'white', paddingVertical: 10, fontSize: 16}, styles.TextFont]}>ชำระเงนตอนน</Text>
</Badge>
</TouchableOpacity>
<TouchableOpacity onPress={onPressLater} style={{width: '100%'}}>
<Badge style={[styles.badgeCancel, {paddingTop: 5}]}>
<Text style={[{color: 'rgba(0, 0, 0, 0.5)', fontSize: 16}, styles.TextFont]}>ภายหล</Text>
</Badge>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
}
function PopupOverDue({isVisible, onPress, onCancel, onPressLater, pending_payment}) {
return <Modal visible={isVisible} transparent={true} animationType="none">
<View style={styles.popupNotiContainer}>
<View style={styles.popupNoti}>
<View style={{width: '100%', alignItems: 'center', position: 'relative'}}>
<Icon name='ic_shop_receive' color='#FF2D55' size={70} style={{marginBottom: 10}}/>
<TouchableOpacity onPress={onPressLater} style={{position: 'absolute', right: 0, top: -10}}>
<Text style={[{color: 'rgba(0, 0, 0, 0.5)', fontSize: 20}, styles.TextFont]}>{t('close')}</Text>
</TouchableOpacity>
<Text style={[{color: '#FF2D55', marginBottom: 10, fontSize: 16}, styles.TextFont]}>หนางชำระเกนกำหนด</Text>
<View style={styles.costText}>
<Text style={[{fontSize: 25, fontWeight: '500', textAlign: 'center'}, styles.TextFont]}>{pending_payment}</Text>
<Text style={[{color: '#8A8A8F', fontSize: 18, fontWeight: '400', position: 'absolute', right: 15, bottom: 8}, styles.TextFont]}>บาท</Text>
</View>
<Text style={[{color: '#FF2D55', fontSize: 14, textAlign: 'center'}, styles.TextFont]}>ณมหนางชำระเกนกำหนดแล</Text>
{/*<Text style={[{color: '#FF2D55', fontSize: 14, textAlign: 'center'}, styles.TextFont]}>กรุณาดำเนินการชำระหนี้ตอนนี้</Text>*/}
<Text style={[{color: '#FF2D55', marginBottom: 15, fontSize: 14, textAlign: 'center'}, styles.TextFont]}>กรณาตดตอเจาหนาท</Text>
<TouchableOpacity onPress={onPress} style={{width: '100%'}}>
<Badge style={styles.badgeSubmit}>
<Text style={[{color: 'white', paddingVertical: 10, fontSize: 16}, styles.TextFont]}>{t('ok')}</Text>
</Badge>
</TouchableOpacity>
{/* <TouchableOpacity onPress={onPressLater}>
<Badge style={[styles.badgeCancel, {paddingTop: 5}]}>
<Text style={[{color: 'rgba(0, 0, 0, 0.5)', fontSize: 16}, styles.TextFont]}>ภายหล</Text>
</Badge>
</TouchableOpacity>*/}
</View>
</View>
</View>
</Modal>
}
function PopupNotiFillInMeter({isVisible, onPress, onCancel, onPressLater, notified_meter_at}) {
return <Modal visible={isVisible} transparent={true} animationType="none" key="popup-noti-meter">
<View style={styles.popupNotiContainer}>
<View style={[styles.popupNoti, {paddingHorizontal: 15}]}>
<View style={{width: '100%', alignItems: 'center'}}>
{/*<Icon name='ic_shop_receive' color='#00420A' size={60} style={{marginBottom: 10}}/>*/}
<Image source={require('../../../assets/images/meter_noti_image.png')} style={{width: 70, height: 70 }} resizeMode={'contain'}/>
<Text style={[{color: '#00420A', marginVertical: 5, fontSize: 16}, styles.TextFont]}>กรณาแนบรปและกรอกเลขมเตอรำไฟ</Text>
<Text style={[{color: '#00420A', marginVertical: 5, fontSize: 13, textAlign: 'center'}, styles.TextFont]}>ภายในวนท {notified_meter_at}</Text>
<Text style={[{color: '#00420A', marginVertical: 5, fontSize: 13, textAlign: 'center', marginBottom: 15}, styles.TextFont]}>ขออภยหากลกคาไดงขอมลเรยบรอยแล</Text>
<TouchableOpacity onPress={onPress} style={{width: '100%'}}>
<Badge style={styles.badgeSubmit}>
<Text style={[{color: 'white', paddingVertical: 10, fontSize: 16}, styles.TextFont]}>กรอกขอม</Text>
</Badge>
</TouchableOpacity>
<TouchableOpacity onPress={onPressLater}>
<Badge style={[styles.badgeCancel, {paddingTop: 5}]}>
<Text style={[{color: 'rgba(0, 0, 0, 0.5)', fontSize: 16}, styles.TextFont]}>ภายหล</Text>
</Badge>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
}
class NewsScreen extends Component {
constructor (props) {
super(props)
@ -59,7 +157,7 @@ class NewsScreen extends Component {
is_new: false
}],
due_at: '',
pending_payment: '',
pending_payment: 0,
noti_count: 0,
isFirstTime: true,
user_point: 0,
@ -70,9 +168,20 @@ class NewsScreen extends Component {
scrollY: new Animated.Value(0),
loadMore: false,
loadPage: 1,
last_page: 1,
isLoadmore: false,
fb_is_link: false,
email: '',
visibleNotiElectric: false,
visibleNotiOverDue: false,
visibleNotiMeter: false,
payment_id: null,
is_notified_electric: false,
is_notified_before_due:false,
is_notified_overdue: false,
is_notified_meter: false,
notified_meter_at: moment().format('DD MMM YYYY'),
due_at_payment: moment().format('DD/MM/YYYY')
}
this._onCarouselScroll = this._onCarouselScroll.bind(this)
@ -80,18 +189,51 @@ class NewsScreen extends Component {
}
componentDidMount () {
this.initData()
// this.initData()
// this.checkNotifiedPopup()
}
checkNotifiedPopup = () => {
if (this.props.user) {
checkPaymentMeter()
.then(res => {
if (res.data && res.data.success) {
this.setState({
is_notified_electric: res.data.is_notified_electric,
is_notified_meter: res.data.is_notified_meter,
is_notified_overdue: res.data.is_notified_overdue,
notified_meter_at: res.data.notified_meter_at,
payment_id: res.data.payment_id,
pending_payment: res.data.pending_payment != null ? res.data.pending_payment : 0,
due_at_payment: res.data.payment && res.data.payment.due_at ? res.data.payment.due_at : null,
}, () => {
setTimeout(() => {
this.setState({
visibleNotiElectric: this.state.is_notified_overdue ? false : this.state.is_notified_electric && parseInt(this.state.pending_payment) > 0,
visibleNotiMeter: ((this.state.is_notified_electric && parseInt(this.state.pending_payment) > 0) || this.state.is_notified_overdue) === true ? false : this.state.is_notified_meter,
visibleNotiOverDue: this.state.is_notified_overdue,
})
}, 1000)
})
}
})
}
}
async getUser () {
if (this.props.token != null) {
return await getUserProfile()
.then(res => {
.then(async res => {
if (res.ok) {
console.log("News:: res.data:")
console.log(res.data)
console.log('project id >>>> ', res.data.project_id)
this.checkNotifiedPopup()
if(res.data.project_id){
await this.getAllNewsByProject(res.data.project_id)
}
this.setState({
pending_payment: res.data.pending_payment != null ? res.data.pending_payment : 0,
noti_count: res.data.count_noti,
user_point: res.data.point_balance,
user_project_id: res.data.project_id,
@ -106,26 +248,41 @@ class NewsScreen extends Component {
}
})
} else {
setTimeout(() => {
//setTimeout(() => {
this.setState({
isLoading: false
}, () => {
this.props.appCleanUser()
this.props.appCleanToken()
})
}, 600)
//}, 600)
}
})
}else {
await this.getAllNewsList()
}
return true
}
async getAllNewsByProject(project_id) {
return getNewsByProject(project_id)
.then(res => {
console.log('res >>>>>>> ', res)
this.setNewsData(res)
})
}
async getAllNewsList () {
// return getNews()
return getNewsPage(this.state.loadPage)
.then(res => {
if ((res.data.data).length > 5) {
this.setNewsData(res)
})
}
setNewsData(res) {
if (res.data.data && (res.data.data).length > 5) {
console.log('data >>>>> ', res)
var cut = []
for (let index = 0; index < 5; index++) {
cut.push(res.data.data[index])
@ -136,24 +293,42 @@ class NewsScreen extends Component {
news_head: cut,
new_all: res.data.data,
refreshing: false,
isLoading: false
isLoading: false,
last_page: res.data.last_page
})
} else {
this.setState({
news_head: res.data.data,
new_all: res.data.data,
refreshing: false,
isLoading: false
isLoading: false,
last_page: res.data.last_page
})
}
})
}
initData () {
this.setState({ isLoading: true })
console.log('initData >>> ')
this.setState({
isLoading: true,
loadPage: 1,
last_page: 1,
news_head: [{
title: 'กำลังโหลดข้อมูลข่าว',
content: 'กำลังโหลดข้อมูลข่าว',
date: 'กำลังโหลดข้อมูลข่าว',
is_new: false
}],
new_all: [{
title: 'กำลังโหลดข้อมูลข่าว',
content: 'กำลังโหลดข้อมูลข่าว',
date: 'กำลังโหลดข้อมูลข่าว',
is_new: false
}],
}, () => {
Promise.all([
this.getUser(),
this.getAllNewsList()
// this.getAllNewsList()
])
.then(() => {
let user_id = 0
@ -195,12 +370,38 @@ class NewsScreen extends Component {
this.setState({
isLoading: false
}, () => {
this.props.appCleanUser()
this.props.appCleanToken()
//this.props.appCleanUser()
//this.props.appCleanToken()
})
}, 600)
this.initData()
// this.initData()
})
})
}
setPermission = async () => {
try {
const enabled = await messaging().hasPermission()
if (!enabled) {
await messaging().requestPermission()
}
} catch (error) {
console.log('error', error)
}
}
initNotification = async () => {
await this.setPermission()
const fcmToken = await messaging().getAPNSToken()
if (fcmToken) {
store.dispatch(appSetPushToken(fcmToken))
const resultSendDevice = await registerDevice(fcmToken)
console.log(' re sult register_device =>', resultSendDevice)
if (resultSendDevice.ok && resultSendDevice.data.success) {
store.dispatch(appSetDevice(resultSendDevice.data.device))
}
}
}
_onRefresh = () => {
@ -208,21 +409,59 @@ class NewsScreen extends Component {
refreshing: true, loadPage: 1, loadMore: false
}, () => {
this.initData()
this.initNotification()
// this.checkNotifiedPopup()
})
}
setPaymentLater = () => {
// setPaymentLater()
// .then(res => {
// if(res && res.data && res.data.success){
this.setState({
visibleNotiElectric: false,
visibleNotiOverDue: false
})
if(this.state.is_notified_meter === true){
this.setState({
visibleNotiMeter: true
}, () => {
setTimeout(() => {
this.forceUpdate()
}, 100)
})
}
// }
// })
}
setFillInMeterLater = () => {
// setFillInMeterLater()
// .then(res => {
// if(res && res.data && res.data.success){
this.setState({
visibleNotiMeter: false
})
// }
// })
}
renderNativeItem = ({ item }) => (
<TouchableOpacity style={{ padding: 8, backgroundColor: '#FFFFFF33', height: 85, borderWidth: 1, borderColor: 'white', borderRadius: 5, flexDirection: 'row' }}
onPress={() => {this.props.navigation.navigate('NewsDetail', { news_id: item.id })}}>
<Image source={{ uri: item.url }} defaultSource={require('../../../assets/images/default_small.png')} style={styles.image_style} resizeMode={'contain'}/>
<Image source={item.url ? { uri: item.url } : require('../../../assets/images/default_small.png')} defaultSource={require('../../../assets/images/default_small.png')} style={styles.image_style} resizeMode={'contain'}/>
<View style={{ flex: 1, marginLeft: 8, justifyContent: 'space-between' }}>
<Text style={{ fontSize: 14, color: 'white', width: '100%', }} ellipsizeMode={'tail'} numberOfLines={2}>{item.title}</Text>
<View style={{ flexDirection: 'row' }}>
<Icon name="ic_calendar_alt" size={16} color="white"/>
<Text style={{ flex: 1, fontSize: 12, color: 'white', marginLeft: 5 }}>{item.date}</Text>
<Text style={{ flex: 1, fontSize: 12, color: 'white', marginLeft: 5 }}>{parseDateLocale(item.date)}</Text>
{
item.is_new == true &&
<View style={{ backgroundColor: '#FF9500', height: 20, paddingHorizontal: 10, borderRadius: 10, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 12, color: 'white' }}>{item.type == "promotion" ? t('latest_promotion') : t('latest_news')}</Text>
</View>
}
</View>
</View>
</TouchableOpacity>
@ -232,17 +471,21 @@ class NewsScreen extends Component {
return <TouchableOpacity onPress={() => {
this.props.navigation.navigate('NewsDetail', { news_id: item.id })
}}>
<ImageBackground source={{ uri: item.url }} onError={(e) => { this.props.source = require('../../../assets/images/default_big.png') }} style={styles.imgBg}>
<ImageBackground source={item.url ? { uri: item.url } : require('../../../assets/images/default_big.png')} onError={(e) => { this.props.source = require('../../../assets/images/default_big.png') }} style={styles.imgBg}>
<LinearGradient colors={['rgba(0, 0, 0, 0)', '#000000']}>
<View style={{ padding: 15, }}>
{item.is_new == true ?
<View style={{ backgroundColor: '#FF9500', borderRadius: 10, height: 20, width: 100, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 10 }}><Text style={{ fontSize: 12, color: 'white' }}>{item.type == "promotion" ? t('latest_promotion') : t('latest_news')} </Text></View>
<View style={{ backgroundColor: '#FF9500', borderRadius: 10, height: 23,
alignSelf: 'flex-start', alignItems: 'center', justifyContent: 'center', flexWrap: 'nowrap',
paddingHorizontal: 10 }}>
<Text style={{ fontSize: 12, width: '100%', justifyContent: 'center', alignItems: 'center', color: 'white', flexWrap: 'nowrap' }}>{item.type == "promotion" ? t('latest_promotion') : t('latest_news')} </Text>
</View>
: null }
<Text style={styles.textNewsName} ellipsizeMode={'tail'} numberOfLines={2}>{item.title}</Text>
<View style={{ flexDirection: 'row', marginTop: 5 }}>
<Icon name="ic_calendar_alt" size={14} color="rgba(255, 255, 255, 0.65)"/>
<Text style={{ color: 'rgba(255, 255, 255, 0.65)', fontSize: 12, marginLeft: 5, marginTop: -1 }}>
{item.date}
{parseDateLocale(item.date)}
</Text>
</View>
</View>
@ -251,21 +494,11 @@ class NewsScreen extends Component {
</TouchableOpacity>
}
getDueAt (date) {
let d = moment(date).format('D')
let m = moment(date).format('MM')
let y = parseInt(moment(date).format('Y')) + 543
let new_date = moment().format('DD/MM/Y')
new_date = d + '/' + m + '/' + y
return new_date
}
_onCarouselScroll (e) {
const scrollX = e.nativeEvent.contentOffset.x
this.setState({
position: Math.ceil(scrollX / width)
})
// console.log(this.state.position)
}
@ -276,41 +509,32 @@ class NewsScreen extends Component {
}
loadMoreData = async () => {
const { loadMore } = this.state
if (loadMore) {
return
}
this.setState({ loadMore: true, isLoadmore: true })
let loadpage = this.state.loadPage + 1
/*loading - set loadMore = false when done*/
getNewsPage(loadpage)
if(parseInt(this.state.loadPage) < parseInt(this.state.last_page)){
this.setState({
loadMore: true,
isLoadmore: true,
loadPage: this.state.loadPage + 1
}, () => {
getNewsPage(this.state.loadPage)
.then(res => {
if (res.ok) {
let resData = res.data.data
let news_arr = this.state.new_all
resData.forEach(item => {
// console.log('data >>>>>><<<< ',item);
news_arr.push(item)
})
let news_all = this.state.new_all
let news_arr = news_all.concat(resData)
this.setState({
loadPage: loadpage,
new_all: news_arr,
refreshing: false,
loadMore: false,
isLoadmore: false
isLoadmore: false,
last_page: res.data.last_page
})
}
})
})
}
if (resData.length < 10) {
this.setState({
loadMore: true
})
return
}
}
})
/*loading - set loadMore = false when done*/
}
_keyExtractorNewHead = (item, index) => 'new_head_' + index
@ -326,14 +550,19 @@ class NewsScreen extends Component {
}}>
<NavigationEvents
onDidFocus={() => {
this.setState({ isLoading: true })
let checkNav = this.props.navigation.getParam('isLogin')
this.setState({
isLoading: true
}, () => {
this.initData()
// this.checkNotifiedPopup()
})
/*let checkNav = this.props.navigation.getParam('isLogin')
if (checkNav) {
this.props.navigation.setParams({ isLogin: false })
this.initData()
} else {
this.setState({ isLoading: false })
}
}*/
}}
/>
<BackgroundImage>
@ -347,7 +576,8 @@ class NewsScreen extends Component {
showsVerticalScrollIndicator={false}
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }]
[{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
{useNativeDriver: false}
)}
onMomentumScrollEnd={({ nativeEvent }) => {
if (this.isCloseToBottom(nativeEvent)) {
@ -366,7 +596,11 @@ class NewsScreen extends Component {
onScroll={this._onCarouselScroll}
/>
<View style={{ position: 'absolute', bottom: 10, width: '100%', justifyContent: 'center', flexDirection: 'row' }}>
{(this.state.news_head).map((item, i) => <View key={'news_heade_' + i} style={[{ width: 10, height: 10, borderRadius: 5, backgroundColor: this.state.position == i ? '#269A21' : 'rgba(255,255,255,0.3)', marginHorizontal: 4 }]}></View>)}
{
this.state.news_head ?
(this.state.news_head).map((item, i) => <View key={'news_heade_' + i} style={[{ width: 10, height: 10, borderRadius: 5, backgroundColor: this.state.position == i ? '#269A21' : 'rgba(255,255,255,0.3)', marginHorizontal: 4 }]}></View>)
: <View></View>
}
</View>
</View>
{this.state.auth !== null &&
@ -377,9 +611,9 @@ class NewsScreen extends Component {
<View style={{ flex: 1, alignItems: 'center', padding: 10 }}>
<View>
<Text style={{ color: 'white', fontSize: 16, textAlign: 'center' }}>{t('for_csa_customer')}</Text>
<Text style={{ color: 'white', fontSize: 16, textAlign: 'center' }}>{t('create_account')} {t('to_view_outstanding_balance')}</Text>
<Text style={{ color: 'white', fontSize: 16, textAlign: 'center' }}>{t('login')} {t('to_view_outstanding_balance')}</Text>
</View>
<TouchableOpacity onPress={() => {
{/*<TouchableOpacity onPress={() => {
// this.props.navigation.navigate('Register')
this.props.navigation.navigate('Terms')
}}>
@ -388,8 +622,8 @@ class NewsScreen extends Component {
<Text style={{ fontSize: 16, color: 'white', padding: 5, textAlign: 'center' }}>{t('create_account')}</Text>
</Badge>
</View>
</TouchableOpacity>
<Text style={{ color: 'white', marginTop: 10 }}>{t('or')}</Text>
</TouchableOpacity>*/}
{/* <Text style={{ color: 'white', marginTop: 10 }}>{t('or')}</Text> */}
<TouchableOpacity onPress={() => { this.props.navigation.navigate('Login') }}>
<View>
<Badge style={{ backgroundColor: '#145EB3', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', marginTop: 10, height: null, width: 150 }}>
@ -397,10 +631,26 @@ class NewsScreen extends Component {
</Badge>
</View>
</TouchableOpacity>
{Platform.OS == 'ios' ? <Text style={{ color: 'white', marginTop: 10 }}>{t('or')}</Text> : null}
{Platform.OS == 'ios' ? <View>
<AppleButton
buttonStyle={AppleButton.Style.WHITE}
buttonType={AppleButton.Type.SIGN_IN}
style={{
width: 150,
height: 45,
marginTop: 10,
}}
onPress={ () => {signinApple(() => {
this.initData()
})
}}
/>
</View> : null}
<Text style={{ color: 'white', marginTop: 10 }}>{t('or')}</Text>
<TouchableOpacity onPress={() => {
loginWithFacebook(() => {
this.initData()
})
@ -408,7 +658,7 @@ class NewsScreen extends Component {
loginWithFacebook(() => {
this.initData()
})
}else{
}else
Alert.alert(
"",
"อิเมล์ "+this.state.email+" ยังไม่ได้ลงทะเบียนในระบบ กรุณาสมัครสมาชิก",
@ -435,7 +685,7 @@ class NewsScreen extends Component {
<View style={{ padding: 5 }}>
<View style={[styles.row, { alignItems: 'stretch' }]}>
<View style={styles.custom_card}>
<Card style={{ borderRadius: 5, backgroundColor: '#00420A', borderColor: 'rbga(0,0,0,0)' }}>
<Card style={{ borderRadius: 5, backgroundColor: '#00420A', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
<BackgroundImage_RegisterForm>
<View style={{ flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 10, minHeight: 177 }}>
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
@ -447,7 +697,7 @@ class NewsScreen extends Component {
<Text style={{ color: 'white', fontSize: 28 }}>{this.state.isBilling ? this.state.pending_payment : 'N/A'}</Text>
{/*<Text style={{ color: 'white', fontSize: 12 }}>{parseFloat(this.state.pending_payment) > 0 ?'โปรดชำระก่อนวันที่':'ยังไม่มียอดค้างชำระ'}</Text>*/}
<Text style={{ color: 'white', fontSize: 12, textAlign: 'center' }}>{parseFloat(this.state.pending_payment) > 0 ? t('to_view_outstanding_balance') : t('no_outstanding_balance_yet')}</Text>
{this.state.due_at !== '' && <Text style={{ color: 'white', fontSize: 12 }}>{parseFloat(this.state.pending_payment) > 0 && this.state.due_at !== '' ? this.getDueAt(this.state.due_at) : ''} </Text>}
{this.state.due_at !== '' && <Text style={{ color: 'white', fontSize: 12 }}>{parseFloat(this.state.pending_payment) > 0 && this.state.due_at !== '' ? this.state.due_at : ''} </Text>}
</View>
<TouchableOpacity disabled={!this.state.isBilling} onPress={() => {this.props.navigation.navigate('Bill')}}>
{/*<Badge style={{ backgroundColor: this.state.isBilling ? '#145EB3' : 'gray', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', justifyContent:'center' }}><Text style={{ fontSize: 12, color: 'white' }}>ดูเพิ่มเติม</Text></Badge>*/}
@ -457,7 +707,7 @@ class NewsScreen extends Component {
</BackgroundImage_RegisterForm>
</Card>
</View>
<View style={[styles.custom_card, { paddingLeft: 5 }]}>
<View style={[styles.custom_card]}>
<Card title='' style={{ borderRadius: 5, backgroundColor: '#003114', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
<BackgroundImage_RegisterForm>
<View style={{
@ -471,12 +721,14 @@ class NewsScreen extends Component {
<Icon name='ic_star' color='white' size={24}/>
{/*<Text style={{ color: 'white', fontSize: 14, marginTop:5 }}>คะแนนสะสม</Text>*/}
<Text style={{ color: 'white', fontSize: 14, marginTop: 5 }}>{t('view_points')}</Text>
<Text style={{ color: 'white', fontSize: 28 }}>{this.state.user_point}</Text>
<Text style={{ color: 'white', fontSize: 28 }}>{parseFloat(this.state.user_point).toLocaleString()}</Text>
{/*<Text style={{ color: 'white', fontSize: 18 }}>พอยต์</Text>*/}
<Text style={{ color: 'white', fontSize: 14 }}>{t('point')}</Text>
<TouchableOpacity style={{ marginTop: 5 }} disabled={true} onPress={() => {}}>
{/*<Badge style={{ backgroundColor: 'gray', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', justifyContent:'center' }}><Text style={{ fontSize: 12, color: 'white' }}>แลกคะแนน</Text></Badge>*/}
<Badge style={{ backgroundColor: 'gray', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', justifyContent: 'center' }}><Text style={{ fontSize: 12, color: 'white' }}>{t('redeem')}</Text></Badge>
<TouchableOpacity style={{ marginTop: 5 }}
onPress={() => {this.props.navigation.navigate('Redeem')}}>
<Badge style={{ backgroundColor: '#145EB3', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', justifyContent: 'center' }}>
<Text style={{ fontSize: 12, color: 'white' }}>{t('redeem')}</Text>
</Badge>
</TouchableOpacity>
</View>
</BackgroundImage_RegisterForm>
@ -484,7 +736,6 @@ class NewsScreen extends Component {
</View>
</View>
<View style={[styles.row, { flexWrap: 'wrap', alignItems: 'stretch' }]}>
{this.state.isMeter ?
<View style={[styles.custom_card]}>
<TouchableOpacity disabled={false} onPress={() => {
this.props.navigation.navigate('Meter')
@ -505,11 +756,11 @@ class NewsScreen extends Component {
</Card>
</TouchableOpacity>
</View>
: null}
{this.state.isShipping ?
<View style={[styles.custom_card]}>
<TouchableOpacity disabled={false} onPress={() => {
this.props.navigation.navigate('Object')
this.props.navigation.navigate('Object',{
user:this.props.user
})
}} style={{ flex: 1 }}>
<Card title='' style={{ borderRadius: 5, backgroundColor: '#145EB3', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
<View style={{
@ -527,12 +778,12 @@ class NewsScreen extends Component {
</Card>
</TouchableOpacity>
</View>
: null}
<View style={[styles.custom_card]}>
<TouchableOpacity disabled={false}
onPress={() => { this.props.navigation.navigate('RepairService',{
/*onPress={() => { this.props.navigation.navigate('RepairService',{
user:this.props.user
}) }}
}) }}*/
onPress={() => { this.props.navigation.navigate('Repair')}}
style={{ flex: 1 }}>
<Card title='' style={{ borderRadius: 5, backgroundColor: '#145EB3', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
<View style={{
@ -583,21 +834,59 @@ class NewsScreen extends Component {
data={this.state.new_all}
renderItem={this.renderNativeItem}
keyExtractor={this._keyExtractorNewAll}
// onEndReachedThreshold={0.01}
// onEndReached={this.loadMoreData.bind(this)}
ItemSeparatorComponent={() => {
return <View style={{ width: '100%', height: 8 }}></View>
}}
ListFooterComponent={() => {
if (!this.state.isLoadmore) return null
return (<View style={{ padding: 16, flexDirection: 'row', borderRadius: 10, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="small" color="black"/>
<Text style={{ fontSize: 12, marginLeft: 10, color: 'black' }}>Loading...</Text>
</View>)
return (<ActivityIndicator
size="large"
color={'white'}
/>)
}}
/>
</View>
</ScrollView>
</BackgroundImage>
<IndicatorLoading loadingVisible={this.state.isLoading}/>
<PopupNotiElectric
isVisible={this.state.visibleNotiElectric}
onCancel={() => this.setState({visibleNotiElectric: false})}
onPressLater={() => this.setPaymentLater()}
pending_payment={this.state.pending_payment}
due_at_payment={this.state.due_at_payment}
onPress={() => this.setState({
visibleNotiElectric: false
}, () => {
this.props.navigation.navigate('Bill')
this.setPaymentLater()
})}/>
<PopupOverDue
isVisible={this.state.visibleNotiOverDue}
onCancel={() => this.setState({visibleNotiOverDue: false})}
onPressLater={() => this.setPaymentLater()}
pending_payment={this.state.pending_payment}
onPress={() => this.setState({
visibleNotiOverDue: false
}, () => {
// this.props.navigation.navigate('Payment', {payment_id: this.state.payment_id})
this.props.navigation.navigate('Bill')
this.setPaymentLater()
})}/>
<PopupNotiFillInMeter
isVisible={this.state.visibleNotiMeter}
onCancel={() => this.setState({visibleNotiMeter: false})}
onPressLater={() => this.setFillInMeterLater()}
notified_meter_at={this.state.notified_meter_at}
onPress={() => this.setState({
visibleNotiMeter: false
}, () => {
this.props.navigation.navigate('Meter')
this.setFillInMeterLater()
})}
/>
</LinearGradient>
)
}
@ -649,6 +938,51 @@ const styles = StyleSheet.create({
custom_card: {
width: '50%', paddingHorizontal: 5,
// width: '100%'
},
popupNoti: {
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 5,
marginHorizontal: 50,
paddingVertical: 20,
paddingHorizontal: 30,
maxWidth: 300,
width: '100%'
},
popupNotiContainer: {
backgroundColor: 'rgba(0,0,0,0.6)',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
width: '100%',
height: '100%',
flex: 1
},
costText: {
backgroundColor: '#EFEFF4',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 5,
borderRadius: 5,
width: '100%',
marginBottom: 10
},
badgeCancel: {
backgroundColor: 'white',
alignItems: 'center',
width: '100%'
},
badgeSubmit: {
backgroundColor: '#145EB3',
borderRadius: 5,
marginBottom: 10,
alignItems: 'center',
width: '100%',
height: 'auto'
},
TextFont: {
fontFamily: 'Prompt-Regular',
}
})
@ -656,5 +990,15 @@ const mapDisPatchToProps = state => {
return state.app
}
const setUser = dispatch => bindActionCreators({ appSetToken, appSetPushToken, appSetDevice, appSetUser, appCleanToken, appCleanUser, appSetNotification, appSetProjectID }, dispatch)
const setUser = dispatch => bindActionCreators({
appSetToken,
appSetPushToken,
appSetDevice,
appSetUser,
appCleanToken,
appCleanUser,
appSetNotification,
appSetProjectID,
setPaymentLater
}, dispatch)
export default connect(mapDisPatchToProps, setUser)(NewsScreen)

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react'
import {View, ScrollView, StyleSheet, Linking, Button, TouchableOpacity, Alert} from 'react-native';
import {View, ScrollView, StyleSheet, Linking, Button, TouchableOpacity, Alert, Platform, Modal, ImageBackground} from 'react-native';
import Image from 'react-native-fast-image'
import { WebView } from 'react-native-webview';
import { Body, Badge, List, ListItem, Right, Title } from 'native-base'
@ -10,9 +10,12 @@ import { BackgroundImage } from '../../components/BackgroundImage'
import { getNewsDetail } from '../../api/UserApi';
import IndicatorLoading from '../../components/IndicatorLoading';
import { t } from '../../utils/i18n'
import parseDateLocale from '../../utils/parseDateLocale';
import ImageView from 'react-native-image-view';
import {NavigationActions} from "react-navigation";
import Config from 'src/utils/Config'
import Carousel from "../room/RoomDetail";
import {sliderWidth} from "../../styles/SliderEntry.style";
var uri = null;
const injectScript = `
(function () {
@ -41,11 +44,11 @@ export default class NewsDetailScreen extends Component {
};
componentWillUnmount() {
/*componentWillUnmount() {
if(this.props && this.props.navigation && this.props.navigation.state && this.props.navigation.state.params && this.props.navigation.state.params.getNotification){
this.props.navigation.state.params.getNotification()
}
}
}*/
getNewsData(){
this.setState({
@ -54,26 +57,34 @@ export default class NewsDetailScreen extends Component {
getNewsDetail(this.state.news_id)
.then(res => {
if(res.ok){
if(res.data.data){
this.setState({
isLoading: false,
news_detail: res.data.data
})
}else{
}else {
console.log('ถูกยกเลิกเผยแพร่ข่าว')
Alert.alert('','ถูกยกเลิกเผยแพร่ข่าว', [{
text: t('ok'),
onPress: () => {
console.log('press')
this.setState({
isLoading: false,
news_detail: [
{
title: '',
content: '',
style: '',
is_new: true,
date:'',
url:'',
}
],
news_detail: {}
})
Alert.alert('','ถูกยกเลิกเผยแพร่ข่าว')
}
}])
}
}else{
Alert.alert('','ถูกยกเลิกเผยแพร่ข่าว', [{
text: t('ok'),
onPress: () => {
this.setState({
isLoading: false,
news_detail: {}
})
}
}])
// alert('ถูกยกเลิกเผยแพร่ข่าว')
// this.context.router.goBack()
@ -82,6 +93,25 @@ export default class NewsDetailScreen extends Component {
}
render() {
let source_webview = {};
source_webview = {
baseUrl: '',
// uri: `${Config.API_BASE_URL_POWER_CONDO_PROD}/news/${this.state.news_id}/detail`,
uri: `${Config.API_BASE_URL_POWER_CONDO_DEV}/news/${this.state.news_id}/detail`
}
// if(Platform.OS === 'android'){
// source_webview = {
// baseUrl: '',
// uri: `${Config.API_BASE_URL_POWER_CONDO_DEV}/news/${this.state.news_id}/detail`
// }
// }else {
// source_webview = {
// baseUrl: '',
// html: `${this.state.news_detail && this.state.news_detail.style ? this.state.news_detail.style : ''}<div id="content_detail"><meta charset="UTF-8"> ${this.state.news_detail && this.state.news_detail.content ? this.state.news_detail.content : ""} </div>`
// }
// }
return (
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
flex: 1,
@ -89,29 +119,36 @@ export default class NewsDetailScreen extends Component {
height: null
}}>
<BackgroundImage>
{
Platform.OS === 'android' &&
<ImageView
images={[{source: {uri: this.state.news_detail != null && this.state.news_detail.url }}]}
images={[{source: {uri: this.state.news_detail != null && this.state.news_detail.url ? this.state.news_detail.url : '' }}]}
imageIndex={0}
isVisible={this.state.isImageViewVisible}
animationType={'fade'}
onClose={() => {this.setState({isImageViewVisible: false})}}
/>
}
<View>
<TouchableOpacity onPress={() => {this.setState({isImageViewVisible: true})}}>
<Image source={{ uri: this.state.news_detail != null && this.state.news_detail.url }} style={styles.imgBg} />
<Image source={{ uri: this.state.news_detail != null && this.state.news_detail.url ? this.state.news_detail.url : '' }} style={styles.imgBg} />
</TouchableOpacity>
</View>
<View style={{ backgroundColor: 'white', padding: 15 }}>
<View style={{ flexDirection: 'row' }}>
<Text style={{ color: '#00420A', fontSize: 16, }}>{this.state.news_detail.title}</Text>
<Text style={{ color: '#00420A', fontSize: 16, }}>{this.state.news_detail != null && this.state.news_detail.title}</Text>
</View>
<View style={{ flexDirection: 'row', marginTop: 5 }}>
<View style={{ width: '50%', flexDirection: "row", marginTop: 5 }}>
<Icon name="ic_event_note" size={16} color="#00420A" />
<Text style={{ marginLeft: 5, color: '#00420A', fontSize: 12, }}>{this.state.news_detail.date}</Text>
{
this.state.news_detail &&
<Text style={{ marginLeft: 5, color: '#00420A', fontSize: 12, }}>{parseDateLocale(this.state.news_detail.date)}</Text>
}
</View>
<View style={{ width: '50%', flexDirection: "row", flex: 1, justifyContent: 'flex-end' }}>
{this.state.news_detail.is_new == true ? <Badge style={{ backgroundColor: '#FF9500', borderRadius: 50, paddingLeft: 10, paddingTop: 5 }}>
<Text style={{ fontSize: 12, color: 'white' }}>{t('latest_news')} </Text>
{this.state.news_detail && this.state.news_detail.is_new == true ? <Badge style={{ backgroundColor: '#FF9500', borderRadius: 50, paddingLeft: 10, paddingTop: 5 }}>
<Text style={{ fontSize: 12, color: 'white' }}>{this.state.news_detail.type === 'promotion' ? t('latest_promotion') : t('latest_news')} </Text>
</Badge> : null}
</View>
</View>
@ -127,26 +164,55 @@ export default class NewsDetailScreen extends Component {
flex: 1,
}}
originWhitelist={['*']}
source={{ baseUrl: '', html: `${this.state.news_detail.style}<div id="content_detail"><meta charset="UTF-8">`+this.state.news_detail.content+'</div>' }}
// source={{baseUrl: '', html: `${this.state.news_detail && this.state.news_detail.style ? this.state.news_detail.style : ''}<div id="content_detail"><meta charset="UTF-8"> ${this.state.news_detail && this.state.news_detail.content ? this.state.news_detail.content : ""} </div>` }}
source={source_webview}
ref={(ref) => { this.webview = ref; }}
javaScriptEnabled={true}
domStorageEnabled={true}
// onShouldStartLoadWithRequest={(navState)=>{ //open external browser for android
// console.log('onShouldStartLoadWithRequest >>>>>> ',navState);
// Linking.openURL(navState.url)
// return false;
// }}
onMessage={(event) => {
if(event.nativeEvent.data){
let data = JSON.parse(event.nativeEvent.data);
if(data.video_id){
Linking.openURL(`https://youtube.com/embed/${data.video_id}`);
}
}
}}
onNavigationStateChange={(event) => {
/*onNavigationStateChange={(event) => {
console.log('onNavigationStateChange >>>>>> ',event);
if (event.url.startsWith("http")) {
this.webview.stopLoading();
this.webview.goBack();
Linking.openURL(event.url);
}
}}
}}*/
/>
</BackgroundImage>
{
Platform.OS === 'ios' &&
<Modal animationType="none"
transparent={true}
visible={this.state.isImageViewVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{flex:1,backgroundColor: 'rgba(0,0,0,.9)', justifyContent: 'center', alignItems: 'center', width: '100%'}}>
<TouchableOpacity style={{height: 80,width: 80, position: 'absolute', zIndex: 1000, right: -25, top: '6%'}}
onPress={() => {this.setState({isImageViewVisible:false})}}
>
<Icon name='ic_add' size={36} color='white' style={{transform:[{rotate:'45deg'}]}}/>
</TouchableOpacity>
<View style={{width: '90%', justifyContent: 'center', height: '100%'}}>
<Image source={{ uri: this.state.news_detail != null && this.state.news_detail.url ? this.state.news_detail.url : '' }}
style={{flex: 1}}
resizeMode={'contain'}
/>
</View>
</View>
</Modal>
}
<IndicatorLoading loadingVisible={this.state.isLoading}/>
</LinearGradient>
)
@ -167,5 +233,11 @@ const styles = StyleSheet.create({
textAlign: 'center',
fontSize: 12
},
backgroundImage: {
flex: 1,
width: null,
height: null,
resizeMode: 'cover'
}
})

View File

@ -1,5 +1,5 @@
import React, {Component} from 'react'
import {FlatList, View, TouchableOpacity, RefreshControl, ScrollView, ActivityIndicator} from 'react-native'
import {FlatList, View, TouchableOpacity, RefreshControl, ScrollView, ActivityIndicator, SafeAreaView} from 'react-native'
import Image from 'react-native-fast-image'
import {BackgroundImage} from '../../components/BackgroundImage'
import LinearGradient from 'react-native-linear-gradient';
@ -8,8 +8,9 @@ import { get_notification, news, read_notification} from '../../api/UserApi'
import {bindActionCreators} from 'redux'
import {appSetNotification} from '../../redux/app/action'
import {connect} from 'react-redux';
import moment from "moment";
import { t } from '../../utils/i18n';
import parseDateLocale from '../../utils/parseDateLocale';
import { NavigationEvents } from "react-navigation";
const injectScript = `
(function () {
@ -33,10 +34,138 @@ class NotificationScreen extends Component {
}
_set_read(item) {
switch (item.source_type) {
case 'payment_success':
case 'update_app':
return false;
default:
read_notification(item.id).then(res => {
console.log('read noti => ', res.data.message)
this.navigateNotification(item)
})
}
}
getContentId(item) {
let data = item.data;
let dataJson = JSON.parse(data);
if(dataJson.id){
return dataJson.id;
}else {
return null;
}
}
navigateNotification = (item) => {
switch (item.source_type) {
case 'news':
case 'general':
case 'promotion':
this.props.navigation.navigate('NewsDetail', {
news_id: item.source_id,
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
});
break;
case 'parcels':
if(item.parcel_status === 'PENDING'){
this.props.navigation.navigate('ObjectDetail', {
object_id: item.source_id,
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
})
}else {
this.props.navigation.navigate('Object', {
user: this.props.user,
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
})
}
break;
case 'message':
this.props.navigation.navigate('Question', {
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
});
break;
case 'meter':
this.props.navigation.navigate('Meter', {
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
});
break;
case 'invoice':
case 'invoice_overdue':
this.props.navigation.navigate('Payment', {
payment_id: this.getContentId(item),
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
});
break;
case 'repair':
case 'effect_repair':
case 'effect_responsible':
case 'edit_repair':
case 'appointment_repair':
case 'cancel_repair':
case 'success_repair':
case 'renew_appointment':
this.props.navigation.navigate('RepairHistoryDetail', {
repair_id: this.getContentId(item),
type: item.source_type,
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
})
break;
case 'request_contact':
this.props.navigation.navigate('Question', {
getNotification: () => {
this.setState({
page: 1
}, () => {
this.getNotification()
})
}
})
break;
default:
return false;
}
}
componentDidMount() {
if (this.props.token != null && this.props.user != null) {
@ -67,7 +196,7 @@ class NotificationScreen extends Component {
// console.log('user_noti_id => ', user_noti_id)
if(this.props.token != null){
get_notification(user_noti_id, 1).then(res => {
get_notification(user_noti_id, this.state.page).then(res => {
if (res.data) {
this.setState({
new_noti: res.data.data,
@ -130,76 +259,79 @@ class NotificationScreen extends Component {
});
}
getTypeNoti(source_type) {
getTypeNoti(item) {
let type = 'ข่าวใหม่';
switch (source_type) {
switch (item.source_type) {
case 'news':
case 'general':
type = t('latest_news');
break;
case 'rooms':
type = t('new_room');
break;
case 'parcels':
type = t('new_parcel');
break;
case 'promotion':
type = t('latest_promotion');
break;
case 'message':
type = t('new_message');
break;
case 'invoice':
case 'invoice_overdue':
type = t('bill_payment');
break;
case 'meter':
type = t('meter_noti');
break;
case 'repair':
case 'effect_repair':
case 'effect_responsible':
case 'edit_repair':
case 'appointment_repair':
case 'request_contact':
case 'cancel_repair':
case 'success_repair':
case 'renew_appointment':
type = item.title;
break;
case 'update_app':
type = t('update_app');
break;
case 'payment_success':
type = t('payment_success');
break;
default:
type = t('latest_news');
type = '';
break;
}
return type;
}
getDateNoti(date) {
let d = moment(date).format('D')
let m = moment(date).format('MM')
let y = parseInt(moment(date).format('Y')) + 543
let new_month = 'ม.ค.';
let new_date = d + ' ' + new_month + ' ' + y;
switch (m) {
case '01':
new_month = 'ม.ค.';
break;
case '02':
new_month = 'ก.พ.';
break;
case '03':
new_month = 'มี.ค.';
break;
case '04':
new_month = 'เม.ย.';
break;
case '05':
new_month = 'พ.ค.';
break;
case '06':
new_month = 'มิ.ย.';
break;
case '07':
new_month = 'ก.ค.';
break;
case '08':
new_month = 'ส.ค.';
break;
case '09':
new_month = 'ก.ย.';
break;
case '10':
new_month = 'ต.ค.';
break;
case '11':
new_month = 'พ.ย.';
break;
case '12':
new_month = 'ธ.ค.';
break;
getStatusParcel (status) {
switch (status) {
case 'PENDING':
return t('waiting_for_pickup');
case 'WAIT_PICKUP':
return t('awaiting_payment');
case 'RECEIVE':
return t('paid');
case 'OTHER':
return t('other');
case 'ERROR':
default:
new_month = 'ม.ค.';
break;
return t('contact_front_desk');
}
}
new_date = d + ' ' + new_month + ' ' + y;
return new_date;
displayParcelContent (data) {
console.log('data >>> ', JSON.parse(data.data))
if(data.parcel_status){
return t('status') + ' : ' + this.getStatusParcel(data.parcel_status)
}
return '';
}
renderSeparator() {
@ -218,11 +350,57 @@ class NotificationScreen extends Component {
if (!this.state.refreshing) return null;
return (
<ActivityIndicator
style={{ color: '#000' }}
size="large"
color={'white'}
/>
);
}
getImageCover = (item) => {
if (item.image_path) {
return {uri: item.image_path};
} else {
switch (item.source_type) {
case 'invoice':
return require('../../../assets/images/invoice_icon.png');
case 'invoice_overdue':
return require('../../../assets/images/invoice_overdue_icon.png');
case 'meter':
return require('../../../assets/images/meter_icon.png');
case 'repair':
case 'effect_repair':
case 'effect_responsible':
case 'edit_repair':
case 'request_contact':
case 'cancel_repair':
case 'renew_appointment':
return require('../../../assets/images/repair_noti.png');
case 'appointment_repair':
return require('../../../assets/images/appointment_repair.png');
case 'success_repair':
return require('../../../assets/images/success_repair.png');
default:
return require('../../../assets/images/logo_5.png');
}
}
}
getContent = (item) => {
switch (item.source_type) {
// case 'parcels':
// return this.displayParcelContent(item);
case 'message':
if(item && item.source && item.source.media){
console.log('media >> ', item.source.media)
return <Image style={styles.image} source={item && item.source && item.source.media ? {uri: item.source.media} : require('../../../assets/images/default_small.png')}/>;
}else {
return item.content;
}
default:
return item.content;
}
}
_keyExtractorNewNoti = (item, index) => 'new_noti_'+index
render() {
@ -234,17 +412,30 @@ class NotificationScreen extends Component {
resizeMode: 'cover'
}}>
<BackgroundImage>
<ScrollView contentContainerStyle={styles.contentContainer}
{/*<ScrollView contentContainerStyle={styles.contentContainer}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
>
>*/}
<View style={styles.container}>
<NavigationEvents
onWillFocus={payload => {
this._onRefresh()
}}
/>
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.new_noti}
refreshing={true}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
keyExtractor={this._keyExtractorNewNoti}
ListEmptyComponent={() =>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center', margin: 16,padding:16,borderRadius:5,backgroundColor:'white'}}>
@ -253,48 +444,50 @@ class NotificationScreen extends Component {
}
ItemSeparatorComponent={this.renderSeparator}
ListFooterComponent={this.renderFooter.bind(this)}
onEndReachedThreshold={0.01}
onEndReached={this.loadMoreNoti.bind(this)}
renderItem={({item, rowData, index}) =>
<TouchableOpacity
onPress={() => {
this._set_read(item),
this.props.navigation.navigate('NewsDetail', {
this._set_read(item)
/*this.props.navigation.navigate('NewsDetail', {
news_id: item.source_id,
getNotification: () => this.getNotification()
})
})*/
}}
key={index}
delayPressIn={50}
activeOpacity={0.8}
style={[item.is_read === false ? styles.isReadFalse : styles.isReadTrue]}
style={[ item && item.is_read === false ? styles.isReadFalse : styles.isReadTrue]}
>
<View style={styles.viewimages} key={index}>
<Image style={styles.image} //source={{uri: rowData.image}}
source={item.url ? {uri: item.url} : require('../../../assets/images/news_test.png')}
source={this.getImageCover(item)}
defaultSource={require('../../../assets/images/default_small.png')}
/>
<View style={styles.viewcontainer}>
<Text style={{fontSize: 14, color: '#145EB3', marginBottom: 3,}}>
{/*{this.getTypeNoti(item.source_type)}*/}
{
item.source &&
item.source.content_type &&
item.source.content_type == 'general' ? t('latest_news') : t('latest_promotion')
item && item.source_type && this.getTypeNoti(item)
}
</Text>
<Text numberOfLines={2} style={{fontSize: 14, color: 'black', marginBottom: 3,}}>
{item.title}
<Text
numberOfLines={item.source_type === 'payment_success' ? 0 : 3}
style={{fontSize: 14, color: 'black', marginBottom: 3,}}>
{this.getContent(item)}
</Text>
<Text style={{fontSize: 10, color: 'rgba(0, 0, 0, 0.5)',}}>
{this.getDateNoti(item.notified_at)}
{ item && item.notified_at && parseDateLocale(item.notified_at, 'D MMM Y, HH:mm')}
</Text>
</View>
</View>
</TouchableOpacity>
}
/>
</SafeAreaView>
</View>
</ScrollView>
{/*</ScrollView>*/}
</BackgroundImage>
</LinearGradient>
)

View File

@ -4,7 +4,7 @@ import Image from 'react-native-fast-image'
import { FlatList } from 'react-native-gesture-handler';
import Text from '../../components/Text';
import Icon from '../../components/Icon'
import {getObjectMessage} from '../../api/UserApi'
import {getObjectMessage, getRoomParcel} from '../../api/UserApi'
import moment from 'moment';
import IndicatorLoading from '../../components/IndicatorLoading';
import { NavigationEvents } from 'react-navigation'
@ -18,7 +18,9 @@ export default class MessageObject extends Component {
this.state = {
isRefreshing: false,
isLoading: true,
message_list:[]
message_list:[],
users:[],
roomIds:[],
};
this.statusText = this.statusText.bind(this)
@ -27,23 +29,55 @@ export default class MessageObject extends Component {
componentDidMount() {
// this.getObject()
const { navigation } = this.props
const users_state = navigation.getParam('user', 'NO ITEM')
this.state.users = users_state
this.state.roomIds = new Array()
if(users_state){
let rooms = users_state.room ? users_state.room : null
let rooms_list = rooms != null ? rooms.split(",") : []
var arrayLength = rooms_list.length;
let self = this;
for (var i = 0; i < arrayLength; i++) {
getRoomParcel(rooms_list[i])
.then(res => {
if(res.ok){
let result_data = new Array()
result_data = res.data.data
self.state.roomIds.push(result_data.id)
}
})
}
}
}
getObject(){
this.setState({
isLoading: true
})
}, () => {
getObjectMessage()
.then(res => {
if(res.ok){
if(res.ok && res.data){
// let parcel_data = new Array()
// parcel_data=res.data.data
// var roomIds = this.state.roomIds
// var filteredArray = new Array()
// if(roomIds.length > 0){
// filteredArray = parcel_data.filter(function(itm){
// return roomIds.indexOf(itm.room_id) > -1;
// })
this.setState({
message_list: res.data.data,
})
}
})
this.setState({
isLoading: false
})
})
}
statusColor(status){
@ -69,6 +103,8 @@ export default class MessageObject extends Component {
return t('awaiting_payment')
case 'RECEIVE':
return t('paid')
case 'OTHER':
return t('other')
case 'ERROR':
default:
return t('contact_front_desk')
@ -79,8 +115,8 @@ export default class MessageObject extends Component {
_renderItem = ({item,index}) => (
<TouchableOpacity onPress={() => {this.props.navigation.navigate('ObjectDetail',{object_id: item.id})}}
disabled={item.status == 'PENDING' ? false : true}
style={{opacity:item.status == 'PENDING' ? 1 : 0.5}}>
disabled={item.status == 'PENDING' || item.status === 'wait_customer_code' ? false : true}
style={{opacity:item.status == 'PENDING' ? 0.5 : 1}}>
<View style={{paddingHorizontal:16,height: 88,backgroundColor:'white',borderWidth:1,borderColor:'#EAEAF4'}}>
<View style={{flex:1,flexDirection:'row',alignItems:'center'}}>
<View style={{height: 64,width: 64,justifyContent:'center',marginRight:8}}>
@ -89,11 +125,19 @@ export default class MessageObject extends Component {
<View style={{flex:1,justifyContent:'center'}}>
<View style={{flexDirection:'row',justifyContent:'space-between'}}>
<Text style={styles.textTitle} numberOfLines={1}>{item.parcel_name}</Text>
<Text>{item.code != null && t('confirmation_code')}</Text>
<Text>
{((item.code != null) && (item.status != 'PENDING' && item.status != 'OTHER' && item.status != 'ERROR') ) ? t('confirmation_code'): '' }
</Text>
</View>
<View style={{flexDirection:'row',justifyContent:'space-between'}}>
<Text style={styles.textTitle} numberOfLines={1}>{t('consignee')} : { item.customer ? item.customer.name : "" }</Text>
<Text style={{fontWeight: 'bold',fontSize: 18}}>{item.code != null && item.code}</Text>
<Text style={styles.textTitle} numberOfLines={1}>{t('consignee')} : { item.customer_name ? item.customer_name.length > 22 ? item.customer_name.substring(0, 22) + '...' : item.customer_name : "" }</Text>
<Text style={{fontWeight: 'bold',fontSize: 18}}>
{((item.code != null)&&(item.status != 'PENDING' && item.status != 'OTHER' && item.status != 'ERROR')) ? item.code: '' }
</Text>
</View>
<View style={{flexDirection:'row',justifyContent:'space-between'}}>
<View style={{justifyContent:'center',alignItems:'center',flexDirection:'row'}}>

View File

@ -24,6 +24,12 @@ export default class MessageObjectDetail extends Component {
this.getObjectDetail()
}
componentWillUnmount() {
if(this.props && this.props.navigation && this.props.navigation.state && this.props.navigation.state.params && this.props.navigation.state.params.getNotification){
this.props.navigation.state.params.getNotification()
}
}
getObjectDetail(){
getObjectMessageByID(this.state.object_id)
.then(res => {
@ -88,7 +94,7 @@ export default class MessageObjectDetail extends Component {
</View>
<View style={{marginVertical:16,height: 1,backgroundColor:'silver',width: '100%'}}/>
<Text style={styles.textTitle}></Text>
<Text style={styles.textBaclk}>{this.state.object_data.customer != null && this.state.object_data.customer.name}</Text>
<Text style={styles.textBaclk}>{this.state.object_data.customer_name != null && this.state.object_data.customer_name}</Text>
{/*<View style={{marginVertical:16,height: 1,backgroundColor:'silver',width: '100%'}}/>
<View style={{flexDirection:'row',justifyContent:'space-between'}}>
<View>

View File

@ -4,33 +4,48 @@ import Text from '../../components/Text';
import Signature from 'react-native-signature-canvas';
import {postSignatureImage} from '../../api/UserApi';
import { t } from '../../utils/i18n';
import SignaturePad from 'react-native-signature-pad';
export default class SignaturePadScreen extends Component {
constructor(props) {
super(props);
this.state = {
signature: null,
object_id: this.props.navigation.getParam('object_id','no-id')
object_id: this.props.navigation.getParam('object_id','no-id'),
keySign: 1
};
this.signPad = React.createRef();
}
handleSignature = signature => {
if(signature === '' || !signature){
Alert.alert(null, t('please_sign'), [{text: 'ok'}])
}else {
let param = {
id: this.state.object_id,
image: signature
}
console.log('-----------> handle signature')
console.log('-----------> handle signature', signature);
this.setState({ signature },() => {
postSignatureImage(param)
.then(res => {
if(res.ok){
Alert.alert(null,'บันทึกสำเร็จ',[{text: t('ok')}])
Alert.alert(null,t('save_success'),[{text: t('ok')}])
this.props.navigation.navigate('Object')
}else{
Alert.alert(null,'บันทึกไม่สำเร็จ กรุณาลองอีกครั้ง',[{text: t('ok')}])
Alert.alert(null,t('save_fail_and_try'),[{text: t('ok')}])
}
})
});
}
};
clearSignPad = () => {
this.setState({
keySign: this.state.keySign + 1
})
};
render() {
@ -39,6 +54,7 @@ export default class SignaturePadScreen extends Component {
background-color: #269A21;
color: #FFF;
}`;
return (
<View style={{flex:1}}>
{/*image show signature when save*/}
@ -51,18 +67,31 @@ export default class SignaturePadScreen extends Component {
/>
) : null}
</View>*/}
<Signature
ref={(c) => { this._signature = c }}
onOK={this.handleSignature}
descriptionText="ลายเซ็น"
clearText="ล้าง"
confirmText="บันทึกรูป"
webStyle={signatureStyle}
/>
{/*<TouchableOpacity style={{margin:16,height: 40,backgroundColor:'#269A21',justifyContent:'center',alignItems:'center',borderRadius:5}}*/}
{/*onPress={() => {this._signature.onOK()}}>*/}
{/*<Text style={{color:'white'}}>ยืนยัน</Text>*/}
{/*</TouchableOpacity>*/}
{/*<Signature*/}
{/*ref={(c) => { this._signature = c }}*/}
{/*onOK={this.handleSignature}*/}
{/*descriptionText="ลายเซ็น"*/}
{/*clearText="ล้าง"*/}
{/*confirmText="บันทึกรูป"*/}
{/*webStyle={signatureStyle}*/}
{/*/>*/}
<View style={{flex: 0.95, marginVertical: 10, marginHorizontal: 15, borderWidth: 1, borderColor: '#e8e8e8'}}>
<SignaturePad ref={this.signPad} key={this.state.keySign}/>
</View>
<View style={{flex: 0.05, flexDirection: 'row', alignItems: 'center', marginBottom: 15, marginHorizontal: 15, justifyContent: 'space-between'}}>
<TouchableOpacity style={{backgroundColor:'#269A21',borderRadius:5, marginRight: 10, justifyContent: 'center', alignItems: 'center', paddingVertical: 5, paddingHorizontal: 35}}
onPress={() => { this.clearSignPad() }}>
<Text style={{color:'white'}}>{t('clear_signature')}</Text>
</TouchableOpacity>
<Text style={{ opacity: 0.4 }}>{t('signature')}</Text>
<TouchableOpacity style={{backgroundColor:'#269A21',borderRadius:5, marginLeft: 10, justifyContent: 'center', alignItems: 'center', paddingVertical: 5, paddingHorizontal: 20}}
onPress={() => { this.handleSignature(this.signPad.current.state.base64DataUrl) }}>
<Text style={{color:'white'}}>{t('save_signature')}</Text>
</TouchableOpacity>
</View>
</View>
);
}

View File

@ -2,12 +2,12 @@ import React, { Component } from 'react'
import {
View,
ScrollView,
Image,
TouchableOpacity,
Platform,
KeyboardAvoidingView,
Alert
} from 'react-native'
import Image from 'react-native-fast-image'
import Icon from '../../components/Icon'
import { Picker } from 'native-base'
import { BackgroundImage_RegisterForm } from '../../components/BackgroundImage_RegisterForm'
@ -56,31 +56,42 @@ class EditProfileScreen extends Component {
componentDidMount () {
const { navigation } = this.props
const users_state = navigation.getParam('user', 'NO ITEM')
const image = navigation.getParam('image', 'NO ITEM')
console.log("defaultImage",image);
if(image != null ){
this.setState({
image_url :image
})
}
// console.log('check user state ----------- ',users_state)
if(users_state.gender == null || users_state.gender == 'null'){
console.log('NULL');
// this.state.user.show_birth_date = users_state.birth_date;
this.setState({
user: {
gender: 'male',
...users_state
name: users_state.name,
...users_state,
}
})
}else{
console.log('NOT NULL');
this.setState({
user: users_state
user: {
...users_state,
name: users_state.name
}
})
}
this.getProjectList()
// this.getProjectList()
}
getProjectList() {
project()
.then(res => {
if (res.ok) {
return this.setState({
if (res.ok && res.data && res.data.data) {
this.setState({
project_list: res.data.data,
selected_project: res.data.data[0].id
})
@ -100,22 +111,49 @@ class EditProfileScreen extends Component {
}
edit_profile () {
// console.log('send user data for edit ----------> ',this.state.user);
if(this.state.user.password != null || this.state.user.password != ''){
if(this.state.user.password === this.state.user.confirm_password){
edit_profile(this.state.user).then(res => res.data)
edit_profile(this.state.user)
.then(res => {
this.props.appSetUser(res)
if(res.ok){
this.props.appSetUser(res.data)
Alert.alert(t('save_success'), '', [{
text: 'ok',
onPress: () => {
this.props.navigation.navigate('Profile')
}
}])
}else {
Alert.alert(t('save_fail_and_try'), '', [{
text: 'ok',
onPress: () => {
this.props.navigation.navigate('Profile')
}
}])
}
})
}else{
Alert.alert('รหัสผ่านไม่ถูกต้อง',`รหัสผ่านใหม่ไม่ตรงกับรหัสยืนยัน\nกรุณาลองอีกครั้ง`)
}
}else{
edit_profile(this.state.user).then(res => res.data)
edit_profile(this.state.user)
.then(res => {
this.props.appSetUser(res)
if(res.ok){
this.props.appSetUser(res.data)
Alert.alert(t('save_success'), '', [{
text: 'ok',
onPress: () => {
this.props.navigation.navigate('Profile')
}
}])
}else {
Alert.alert(t('save_fail_and_try'), '', [{
text: 'ok',
onPress: () => {
this.props.navigation.navigate('Profile')
}
}])
}
})
}
}
@ -127,21 +165,24 @@ class EditProfileScreen extends Component {
cropping: true,
includeBase64: true
}).then(image => {
// console.log('received base64 image', image)
console.log('received base64 image', image)
let image_profile = {
uri: image.path,
type: image.mime,
name: 'image_profile.jpg',
}
let image_data = { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height };
this.setState({
image_url: { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height },
image_url: image_profile,
images: null,
user: {
...this.state.user,
profile_image_id: image_profile
profile_image_id: image_profile,
profile_image: image_data
}
})
}).catch(e => alert(e))
})
}
onTakeCamera () {
@ -149,9 +190,12 @@ class EditProfileScreen extends Component {
cropping: true,
width: 300,
height: 300,
includeExif: true
includeExif: true,
includeBase64: true
}).then(image => {
// console.log('received image', image)
console.log('received image', image)
let image_data = { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height };
let image_profile = {
uri: image.path,
type: image.mime,
@ -162,10 +206,11 @@ class EditProfileScreen extends Component {
images: null,
user: {
...this.state.user,
profile_image_id: image_profile
profile_image_id: image_profile,
profile_image: image_data
}
})
}).catch(e => alert(e))
})
}
render () {
@ -173,18 +218,24 @@ class EditProfileScreen extends Component {
const users = navigation.getParam('user', 'NO ITEM')
// console.log('users :', users);
return (
<View style={{ flex: 1, backgroundColor: '#00420A' }}>
<KeyboardAvoidingView style={{flex:1}} keyboardVerticalOffset={Platform.OS == 'ios' ? 75 : 0} behavior={Platform.OS == 'ios' ? "padding" : ""} enabled>
<KeyboardAvoidingView style={{flex:1}}
keyboardVerticalOffset={Platform.OS == 'ios' ? 75 : 0}
behavior={Platform.OS == 'ios' ? 'padding' : ''}
ref={(view) => {this.scrollView = view;}}
>
<View style={{ flex: 1, backgroundColor: '#00420A'}}>
<BackgroundImage_RegisterForm>
<ScrollView style={{ flexDirection: 'column' }}>
<ScrollView style={{ flex: 1, height: '100%' }}>
<View style={{ flexDirection: 'column', flex: 1}}>
<View>
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
flex: 1,
// flex: 1,
width: null,
height: null,
resizeMode: 'cover'
}}>
<View style={{ flex: 1, paddingVertical: 20, alignItems: 'center' }}>
<View style={{ width: '30%' }}>
<View style={{ paddingVertical: 20, alignItems: 'center' }}>
<View>
<TouchableOpacity
style={{
backgroundColor: '#FFF',
@ -192,7 +243,7 @@ class EditProfileScreen extends Component {
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
right: '-5%',
right: '0%',
top: '0%',
zIndex: 1
}}
@ -216,21 +267,16 @@ class EditProfileScreen extends Component {
<Icon name={'ic_outline_camera'} size={20} color={'#8BC34A'}/>
</TouchableOpacity>
<Image
style={{
width: 120,
height: 120,
borderRadius: 60,
borderColor: 'white',
borderWidth: 2
}}
source={this.state.image_url}
style={{width: 120, height: 120, borderRadius: 60, borderColor: 'white', borderWidth: 2}}
source={{ uri: this.state.image_url && this.state.image_url.uri ? this.state.image_url.uri : ''}}
/>
</View>
</View>
</LinearGradient>
<View style={{ flex: 1, height: '100%' }}>
<View style={{ flex: 1 }}>
<View style={[styles.form]}>
</View>
<View style={{ flexDirection: 'column' , padding: 15, paddingTop: 5, paddingBottom: 0,}}>
<View>
<Text style={styles.headerTitle}>{t('profile')}</Text>
<View style={styles.row}>
<CustomInput
@ -243,7 +289,8 @@ class EditProfileScreen extends Component {
this.setState({
user: {
...this.state.user,
name: text
name: text,
name_th: text
}
})
}}/>
@ -264,7 +311,7 @@ class EditProfileScreen extends Component {
})
}}/>
</View>
<View style={styles.row}>
{/*<View style={styles.row}>
<View style={styles.row_grow_first}>
<View
style={{
@ -322,19 +369,20 @@ class EditProfileScreen extends Component {
</View>
</View>
</View>
</View>
<View style={styles.row}>
</View>*/}
{/*<View style={styles.row}>
<View style={styles.row_grow}>
<CustomDatePicker titleText={t('birth_date')} dateText={moment(this.state.user.birth_date).format('YYYY-MM-DD')} handleDate={(data) => {
<CustomDatePicker titleText={t('birth_date')} dateText={moment(this.state.user.show_birth_date).add(543, 'years').format('DD-MM-YYYY')} handleDate={(data) => {
this.setState({
user: {
...this.state.user,
birth_date: moment(data).format('YYYY-MM-DD')
birth_date: moment(data).format('YYYY-MM-DD'),
show_birth_date: moment(data).format('YYYY-MM-DD')
}
})}}/>
</View>
</View>
<View style={styles.row}>
</View>*/}
{/*<View style={styles.row}>
<CustomInput
style={styles.register_input}
labelColor={'white'}
@ -349,7 +397,7 @@ class EditProfileScreen extends Component {
}
})
}}/>
</View>
</View>*/}
<View style={styles.row}>
<CustomInput
style={styles.register_input}
@ -366,8 +414,8 @@ class EditProfileScreen extends Component {
})
}}/>
</View>
<Text style={styles.headerTitle}>{t('accom_info')}</Text>
<View style={styles.row}>
{/*<Text style={styles.headerTitle}>{t('accom_info')}</Text>*/}
{/*<View style={styles.row}>
<View
style={{
flexGrow: 1,
@ -426,8 +474,8 @@ class EditProfileScreen extends Component {
</Picker>
</View>
</View>
</View>
<View style={styles.row}>
</View>*/}
{/*<View style={styles.row}>
<View
style={{
flexGrow: 1,
@ -459,10 +507,6 @@ class EditProfileScreen extends Component {
color: 'white',
height: 40,
}}
textStyle={{
color: 'white',
fontFamily: 'Prompt-Regular'
}}
textStyle={{color:'white',fontFamily:'Prompt-Regular',fontSize:14}}
labelName={t('building')}
placeholder={t('choose_project')}
@ -475,7 +519,7 @@ class EditProfileScreen extends Component {
}
})
}}>
{this.state.building_list.length > 0 && this.state.building_list.map((item,index) => {
{this.state.building_list.map((item,index) => {
return <Picker.Item label={item.room_build} value={item.room_build} key={'building_'+index}/>
})}
</Picker>
@ -499,7 +543,8 @@ class EditProfileScreen extends Component {
})
}}/>
</View>
</View>
</View>*/}
<Text style={styles.headerTitle}>{t('change_password')}</Text>
<View>
<View style={styles.row}>
@ -540,6 +585,9 @@ class EditProfileScreen extends Component {
}}/>
</View>
</View>
</View>
<View>
<View style={styles.buttons}>
<View style={styles.row_grow}>
<CustomButton style={styles.btn_next_register} title={t('complete')}
@ -553,8 +601,8 @@ class EditProfileScreen extends Component {
</View>
</ScrollView>
</BackgroundImage_RegisterForm>
</KeyboardAvoidingView>
</View>
</KeyboardAvoidingView>
)
}
}
@ -609,10 +657,10 @@ const styles = {
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 30,
}
}
};
const mapDisPatchToProps = state => {
return state.app
}
};
const setUser = dispatch => bindActionCreators({ appSetDevice, appSetUser, appCleanUser }, dispatch)
export default connect(mapDisPatchToProps, setUser)(EditProfileScreen)

View File

@ -23,6 +23,7 @@ class ProfileScreen extends Component {
isLoading: false,
user:{},
room:null,
profileImage: require('../../../assets/images/profile.png')
}
this.getUserData = this.getUserData.bind(this)
}
@ -42,10 +43,18 @@ class ProfileScreen extends Component {
.then(res => {
// console.log('user profile -------> ',res);
if(res.ok){
let image = require('../../../assets/images/profile.png')
if (res.data.user.image){
image = {
uri: res.data.user.image ? res.data.user.image.url ? res.data.user.image.url : res.data.user.image : ''
}
}
this.props.user.show_birth_date = res.data.user.birth_date
this.setState({
isLoading: false,
user: res.data.user,
room: res.data.room
room: res.data.room && res.data.room.length > 0 ? res.data.room[0] : null,
profileImage : image,
})
}else{
this.setState({
@ -55,6 +64,31 @@ class ProfileScreen extends Component {
})
}
connectFBSuccess = () => {
this.state.user.fb_is_link = 't';
Alert.alert('Connect with Facebook Success', '', [
{
text: 'ok',
onPress: () => {
this.getUserData()
}
}
])
};
disConnectFBSuccess = () => {
this.state.user.fb_is_link = 'f';
this.state.user.fb_token = null;
Alert.alert('Disconnect with Facebook Success', '', [
{
text: 'ok',
onPress: () => {
this.getUserData()
}
}
])
};
refreshPage() {
window.location.reload(false);
}
@ -69,6 +103,7 @@ class ProfileScreen extends Component {
}}>
<NavigationEvents
onDidFocus={() => {
console.log('getUserData');
this.getUserData()
}}
/>
@ -80,7 +115,7 @@ class ProfileScreen extends Component {
}}>
<Image
style={{ width: 120, height: 120, borderRadius: 60, borderColor: 'white', borderWidth: 2 }}
source={require('../../../assets/images/profile.png')}
source={this.state.profileImage}
/>
</View>
<View style={{ flex: 1, padding: 15, }}>
@ -89,7 +124,7 @@ class ProfileScreen extends Component {
<Text style={{ color: '#8BC34A', marginBottom: 10 }}>{t('profile')}</Text>
<View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('category')}</Text>
<Text style={styles.data_field_style}>{t('individual2')}</Text>
<Text style={styles.data_field_style}>{this.state.user.is_customer ? t('customer') : t('guest')}</Text>
</View>
<View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('name')}</Text>
@ -97,7 +132,7 @@ class ProfileScreen extends Component {
</View>
<View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('email')}</Text>
<Text style={styles.data_field_style}>{this.state.user.email}</Text>
<Text style={styles.data_field_style}>{this.state.user.email ? this.state.email : '-'}</Text>
</View>
<View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('phone2')}</Text>
@ -109,11 +144,11 @@ class ProfileScreen extends Component {
</View>
<View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('gender')}</Text>
<Text style={styles.data_field_style}>{this.state.user.gender=="male"? t('male') : t('female')}</Text>
<Text style={styles.data_field_style}>{this.state.user.gender == "male" || this.state.user.gender == "ชาย" ? t('male') : t('female')}</Text>
</View>
<View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('birth_date')}</Text>
<Text style={styles.data_field_style}>{moment(this.state.user.birth_date).format('DD-MM-YYYY')}</Text>
<Text style={styles.data_field_style}>{this.state.user.birth_date ? moment(this.state.user.birth_date, 'DD-MM-YYYY').add(543, 'years').format('DD MMM YYYY') : ''}</Text>
</View>
</View>
{
@ -144,18 +179,9 @@ class ProfileScreen extends Component {
<View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}>
<Button block style={{ backgroundColor: '#145EB3', marginHorizontal: 15 }}
onPress={() => {
setTimeout( () => {
loginWithFacebook()
setTimeout( () => {
this.state.user.fb_is_link = 't'
this.props.navigation.navigate('Profile',{user:this.state.user})
Alert.alert('Connect with Facebook Success')
},4000);
loginWithFacebook(this.connectFBSuccess)
},1000);
}} >
<Text style={{ color: '#ffffff', fontSize: 14 }}>{t('connect_facebook')}</Text>
</Button>
@ -164,18 +190,7 @@ class ProfileScreen extends Component {
<View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}>
<Button block style={{ backgroundColor: '#145EB3', marginHorizontal: 15 }}
onPress={() => {
disconnectWithFacebook();
setTimeout( () => {
this.state.user.fb_is_link = 'f'
//alert("Disconnected!")
this.props.navigation.replace('Profile',{user:this.state.user})
},3000);
disconnectWithFacebook(this.disConnectFBSuccess);
}}
>
<Text style={{ color: '#ffffff', fontSize: 14 }}>{t('disconnect_facebook')}</Text>
@ -186,7 +201,8 @@ class ProfileScreen extends Component {
<View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}>
<Button block style={{ backgroundColor: '#145EB3', margin:15 }}
onPress={() => { this.props.navigation.navigate('EditProfile',{
user:this.props.user
user:this.state.user,
image:this.state.profileImage,
}) }}>
<Text style={{ color: '#ffffff', fontSize: 14 }}><Icon name={'ic_edit'} size={15}/> {t('edit_profile')} </Text>
</Button>

View File

@ -0,0 +1,199 @@
import React, {Component} from 'react'
import {TouchableOpacity, View, StyleSheet, Text, ScrollView, RefreshControl, Animated, FlatList} from "react-native";
import LinearGradient from "react-native-linear-gradient";
import {BackgroundImage} from "../../components/BackgroundImage";
import IconMaterial from "react-native-vector-icons/MaterialCommunityIcons";
import Image from "react-native-fast-image";
import {NavigationEvents} from "react-navigation";
import {getListReward, getUserProfile} from "../../api/UserApi";
import {bindActionCreators} from "redux";
import {appSetUser} from "../../redux/app/action";
import {connect} from "react-redux";
import IndicatorLoading from "../../components/IndicatorLoading";
class AllRewards extends Component{
constructor(props) {
super(props);
this.state = {
isLoading: false,
refreshing: false,
all_rewards: [
/*{source: require('../../../assets/images/reward_exam1.png'), title: 'อปอปสตาร 100 บาท แถมฟรวนลดตวหน 100... ', point: '1'},
{source: require('../../../assets/images/reward_exam2.png'), title: 'Samosa หอมเครื่องเทศกรอบอร่อย 2 ชิ้น ในราคาเพียง 70 บาท', point: '2'},
{source: require('../../../assets/images/reward_exam1.png'), title: 'เหล่ามินเนียน เตรียมบุกเมเจอร์ ให้สาวกชาวแก๊งค์ให้เก็บสะสม ', point: '3'},
{source: require('../../../assets/images/reward_exam2.png'), title: 'M GEN แลก Points อร่อยคุ้มจาก แมคโดนัลด์', point: '4'},*/
],
point: 0
}
}
initData = () => {
this.setState({
isLoading: true,
refreshing: true
}, () => {
Promise.all([
this.getListReward(),
this.getUserProfile()
]).then(() => {
this.setState({
isLoading: false,
refreshing: false
})
});
})
};
async getListReward () {
let category_id = this.props.navigation && this.props.navigation.state && this.props.navigation.state.params && this.props.navigation.state.params.id ? this.props.navigation.state.params.id : ''
return await getListReward(category_id)
.then(res => {
if(res.ok){
this.setState({
all_rewards: res.data.data
})
}
})
};
async getUserProfile () {
return await getUserProfile()
.then(res => {
if(res.data && res.ok){
this.setState({
point: res.data.point_balance,
}, () => {
let user_data = this.props.user;
user_data = {
...user_data,
point: this.state.point
}
this.props.appSetUser(user_data)
})
}
});
}
_onRefresh = () => {
this.setState({
isLoading: true,
refreshing: true
}, () => {
this.initData()
})
};
_keyExtractor = (item, index) => 'reward_' + index;
renderItem = (item, index) => {
return (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('RewardDetail', {id: item.id})}
style={[styles.rewardContain, {marginRight: index % 2 === 0 ? 10 : 0}, {width: index % 2 === 0 ? '48%' : '49.5%'}]}>
<View style={{flex: 0.8}}>
<Image source={{uri: item.image_reward ? item.image_reward : ''}} style={{height: '100%'}} resizeMode={'contain'} />
</View>
<View style={{flex: 0.2, padding: 8, flexDirection: 'column', justifyContent: 'center'}}>
<Text style={{fontWeight: '600', fontFamily: 'Prompt-Regular',}}>{item.name}</Text>
<Text style={{textAlign: 'right', color: '#FF6122', fontFamily: 'Prompt-Regular', fontWeight: '600'}}>{item.points_to_redeem} Point</Text>
</View>
</TouchableOpacity>
)
};
render() {
return (
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
flex: 1,
width: null,
height: null,
resizeMode: 'cover'
}}>
<NavigationEvents
onDidFocus={() => {
this.setState({
isLoading: true
}, () => {
this.initData()
})
}}
/>
<BackgroundImage>
<LinearGradient start={{x: 0, y: 0}} end={{x: 1, y: 0}} colors={['#FFA800', '#E46F00']}
style={styles.pointContain}
>
<Text style={styles.textStyle}>{this.state.point} Points</Text>
<IconMaterial name="star-circle-outline" color="white" size={40}/>
</LinearGradient>
<ScrollView contentContainerStyle={styles.contentContainer}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
showsVerticalScrollIndicator={false}
scrollEventThrottle={16}
// onScroll={Animated.event(
// [{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }]
// )}
>
<View style={{paddingHorizontal: 8, paddingBottom: 16}}>
<FlatList
data={this.state.all_rewards}
renderItem={({ item, index }) => this.renderItem(item, index)}
showsHorizontalScrollIndicator={false}
keyExtractor={this._keyExtractor}
numColumns={2}
extraData={this.state.all_rewards}
// onScroll={this._onCarouselScroll}
ListEmptyComponent={() =>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center', margin: 16,padding:16,borderRadius:5,backgroundColor:'white'}}>
<Text style={{fontSize: 16}}>No Rewards</Text>
</View>
}
/>
</View>
</ScrollView>
</BackgroundImage>
<IndicatorLoading loadingVisible={this.state.isLoading}/>
</LinearGradient>
);
}
}
const styles = StyleSheet.create({
textStyle: {
color: 'white',
fontFamily: 'Prompt-Regular',
fontSize: 20,
textAlign: 'right',
fontWeight: '500',
marginRight: 5
},
pointContain: {
justifyContent: 'flex-end',
paddingVertical: 12,
paddingHorizontal: 5,
flexDirection: 'row',
alignItems: 'center'
},
rewardContain: {
// flex: 1,
// width: '48%',
height: 300,
backgroundColor: 'white',
borderRadius: 6,
marginTop: 16
}
});
const mapDisPatchToProps = state => {
return state.app
}
const propSet = dispatch => bindActionCreators({
appSetUser,
}, dispatch)
export default connect(mapDisPatchToProps, propSet)(AllRewards)

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