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 # CocoaPods
/ios/Pods/ /ios/Pods/
.vscode
.bundle
android/.settings
android/app/.settings
android/*.hprof

48
App.js
View File

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

View File

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>csareactrn60</name> <name>charoensin</name>
<comment>Project android created by Buildship.</comment> <comment>Project android created by Buildship.</comment>
<projects> <projects>
</projects> </projects>
@ -14,4 +14,15 @@
<natures> <natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature> <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures> </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> </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"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <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="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/> <classpathentry kind="output" path="bin/default"/>
</classpath> </classpath>

View File

@ -20,4 +20,15 @@
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature> <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures> </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> </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" applicationId "th.co.csasset.mobile"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 60 versionCode 84
versionName "2.12" versionName "2.33"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
missingDimensionStrategy 'react-native-camera', 'general'
multiDexEnabled true
} }
splits { splits {
abi { abi {
@ -208,7 +210,10 @@ android {
} }
} }
// def multidex_version = "2.0.1"
dependencies { dependencies {
implementation project(':react-native-permissions')
implementation project(':react-native-camera')
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+" // From node_modules implementation "com.facebook.react:react-native:+" // From node_modules
if (enableHermes) { if (enableHermes) {
@ -223,6 +228,7 @@ dependencies {
implementation "com.google.firebase:firebase-core:16.0.9" implementation "com.google.firebase:firebase-core:16.0.9"
implementation "com.google.firebase:firebase-config:17.0.0" implementation "com.google.firebase:firebase-config:17.0.0"
implementation "com.google.firebase:firebase-messaging:18.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)' // implementation 'com.facebook.android:facebook-android-sdk:[5,6)'
} }
@ -236,4 +242,4 @@ task copyDownloadableDepsToLibs(type: Copy) {
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'

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

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

View File

@ -9,15 +9,17 @@ import com.facebook.react.bridge.JavaScriptExecutorFactory;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
//import com.facebook.reactnative.androidsdk.BuildConfig;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
import com.learnium.RNDeviceInfo.RNDeviceInfo; import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.reactnativecommunity.cameraroll.CameraRollPackage; import com.reactnativecommunity.cameraroll.CameraRollPackage;
import org.reactnative.camera.RNCameraPackage;
// Firebase // Firebase
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage; //import io.invertase.firebase.messaging.ReactNativeFirebaseMessagingPackage;
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage; //import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage; //import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage;
import com.facebook.reactnative.androidsdk.FBSDKPackage; import com.facebook.reactnative.androidsdk.FBSDKPackage;
@ -37,9 +39,10 @@ public class MainApplication extends Application implements ReactApplication {
List<ReactPackage> packages = new PackageList(this).getPackages(); List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example: // Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage()); // packages.add(new MyReactNativePackage());
packages.add(new RNFirebaseNotificationsPackage()); // packages.add(new RNFirebaseNotificationsPackage());
packages.add(new RNFirebaseMessagingPackage()); // packages.add(new ReactNativeFirebaseMessagingPackage());
packages.add(new RNFirebaseRemoteConfigPackage()); // packages.add(new RNFirebaseRemoteConfigPackage());
// packages.add(new RNCameraPackage());
return packages; 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 { ext {
googlePlayServiceVersion = "17.0.0" googlePlayServiceVersion = "17.0.0"
buildToolsVersion = "28.0.3" buildToolsVersion = "28.0.3"
kotlinVersion = "1.5.20"
minSdkVersion = 21 minSdkVersion = 21
compileSdkVersion = 28 compileSdkVersion = 31
targetSdkVersion = 28 targetSdkVersion = 31
} }
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
jcenter() // jcenter()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:3.4.1") classpath('com.android.tools.build:gradle:4.2.2')
classpath 'com.google.gms:google-services:4.2.0' classpath('com.google.gms:google-services:4.3.14')
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // 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 { allprojects {
repositories { repositories {
mavenCentral()
mavenLocal() mavenLocal()
maven { maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
@ -35,9 +39,14 @@ allprojects {
} }
google() google()
jcenter() // jcenter()
maven { url 'https://maven.google.com' } maven { url 'https://maven.google.com' }
maven { url "https://jitpack.io" } 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. ## For more details on how to configure your build environment visit
# 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
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # 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 # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # 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 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
#Fri Apr 07 15:17:20 ICT 2023
android.useAndroidX=true
android.enableJetifier=true
MYAPP_RELEASE_STORE_FILE=charoensin.release.keystore MYAPP_RELEASE_STORE_FILE=charoensin.release.keystore
MYAPP_RELEASE_KEY_ALIAS=charoensin MYAPP_RELEASE_KEY_ALIAS=charoensin
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 MYAPP_RELEASE_STORE_PASSWORD=aabbccddee
MYAPP_RELEASE_KEY_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 distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
# You may obtain a copy of the License at # 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 # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # 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 # 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" # Resolve links: $0 may be a link
APP_BASE_NAME=`basename "$0"` 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. # 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"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 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." location of your Java installation."
fi fi
else 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. 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 Please set the JAVA_HOME variable in your environment to match the
@ -105,84 +140,105 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
MAX_FD="$MAX_FD_LIMIT" # shellcheck disable=SC3045
fi MAX_FD=$( ulimit -H -n ) ||
ulimit -n $MAX_FD warn "Could not query maximum file descriptor limit"
if [ $? -ne 0 ] ; then esac
warn "Could not set maximum file descriptor limit: $MAX_FD" case $MAX_FD in #(
fi '' | soft) :;; #(
else *)
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
fi # shellcheck disable=SC3045
fi ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
# 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" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=$(save "$@") # * --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 # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 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 JAVACMD=$( cygpath --unix "$JAVACMD" )
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")" # 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 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" "$@" 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 not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem http://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@ -14,7 +14,7 @@
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -25,10 +25,14 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% 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. @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" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if %ERRORLEVEL% equ 0 goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 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_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -61,38 +65,26 @@ echo location of your Java installation.
goto fail 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 :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @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 :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

View File

@ -1,4 +1,20 @@
rootProject.name = 'charoensin' 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' include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android') project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-fbsdk' 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 { 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' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
xcodeproj 'csareactrn60'
target 'csareactrn60' do target 'csareactrn60' do
# Pods for csareactrn60 # Pods for csareactrn60
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" 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-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' 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 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' 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 'react-native-fbsdk', :path => '../node_modules/react-native-fbsdk'
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' 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 'FBSDKCoreKit'
pod 'FBSDKLoginKit' pod 'FBSDKLoginKit'
pod 'FBSDKShareKit' pod 'FBSDKShareKit'
#Firebase
pod 'Firebase/Messaging', '~> 6.8.0'
pod 'react-native-view-shot', :path => '../node_modules/react-native-view-shot' pod 'react-native-view-shot', :path => '../node_modules/react-native-view-shot'
pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker' pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker'
use_native_modules! 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 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"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0940" LastUpgradeVersion = "1120"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "NO" parallelizeBuildables = "NO"
@ -55,6 +55,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "csareactrn60-tvOS.app"
BlueprintName = "csareactrn60-tvOS"
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO"> skipped = "NO">
@ -67,17 +76,6 @@
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "csareactrn60-tvOS.app"
BlueprintName = "csareactrn60-tvOS"
ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@ -99,8 +97,6 @@
ReferencedContainer = "container:csareactrn60.xcodeproj"> ReferencedContainer = "container:csareactrn60.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

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

View File

@ -69,6 +69,20 @@
<string>Choose a picture for user profile image or save image.</string> <string>Choose a picture for user profile image or save image.</string>
<key>NSPhotoLibraryUsageDescription</key> <key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to choose photos to upload profile picture and create support ticket.</string> <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> <key>UIAppFonts</key>
<array> <array>
<string>arial.ttf</string> <string>arial.ttf</string>

View File

@ -4,5 +4,9 @@
<dict> <dict>
<key>aps-environment</key> <key>aps-environment</key>
<string>development</string> <string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict> </dict>
</plist> </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", "postinstall": "sh ./fix.sh",
"prod-android": "cd android && ./gradlew assembleRelease", "prod-android": "cd android && ./gradlew assembleRelease",
"run-android": "react-native run-android", "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": { "rnpm": {
"assets": [ "assets": [
@ -18,51 +20,66 @@
] ]
}, },
"dependencies": { "dependencies": {
"@invertase/react-native-apple-authentication": "^1.1.2",
"@react-native-community/cameraroll": "^1.2.1", "@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", "apisauce": "^1.1.0",
"deprecated-react-native-listview": "^0.0.5", "deprecated-react-native-listview": "^0.0.5",
"i18n-js": "^3.5.1", "i18n-js": "^3.5.1",
"intl": "^1.2.5", "intl": "^1.2.5",
"jetifier": "^2.0.0",
"moment": "^2.24.0", "moment": "^2.24.0",
"native-base": "^2.13.8", "native-base": "^2.13.8",
"react": "16.9.0", "react": "16.9.0",
"react-native": "0.61.5", "react-native": "^0.63",
"react-native-action-sheet": "^2.2.0", "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-device-info": "^5.5.7",
"react-native-dropdown-picker": "^5.4.6",
"react-native-easy-grid": "^0.2.2", "react-native-easy-grid": "^0.2.2",
"react-native-elastic-image-slider": "^1.0.0", "react-native-elastic-image-slider": "^1.0.0",
"react-native-elements": "^1.2.0", "react-native-elements": "^1.2.0",
"react-native-fast-image": "^8.1.5", "react-native-fast-image": "^8.1.5",
"react-native-fbsdk": "^1.1.2", "react-native-fbsdk": "^1.1.2",
"react-native-firebase": "^5.5.6",
"react-native-gesture-handler": "^1.4.1", "react-native-gesture-handler": "^1.4.1",
"react-native-hyperlink": "^0.0.16", "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-slider-show": "^1.0.3",
"react-native-image-slideshow": "^1.0.1", "react-native-image-slideshow": "^1.0.1",
"react-native-image-view": "^2.1.5", "react-native-image-view": "^2.1.5",
"react-native-linear-gradient": "^2.5.6", "react-native-linear-gradient": "^2.5.6",
"react-native-modal-datetime-picker": "^7.5.0", "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-picker-dropdown": "^0.1.2",
"react-native-qrcode": "^0.2.7", "react-native-qrcode": "^0.2.7",
"react-native-qrcode-scanner": "^1.5.5",
"react-native-qrcode-svg": "^5.2.0", "react-native-qrcode-svg": "^5.2.0",
"react-native-render-html": "^4.1.2", "react-native-render-html": "^4.1.2",
"react-native-screens": "^2.7.0", "react-native-screens": "^2.7.0",
"react-native-searchable-dropdown": "^1.1.1", "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-snap-carousel": "^3.8.0",
"react-native-splash-screen": "^3.2.0", "react-native-splash-screen": "^3.2.0",
"react-native-svg": "^9.9.3", "react-native-svg": "^9.9.3",
"react-native-switch-toggle": "^1.1.0", "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-vector-icons": "^6.6.0",
"react-native-view-shot": "^3.0.2", "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-navigation": "^3.3.0",
"react-redux": "^7.1.1", "react-redux": "^7.1.1",
"react-select2-native": "^1.3.0",
"redux": "^4.0.4", "redux": "^4.0.4",
"redux-persist": "^5.10.0", "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": { "devDependencies": {
"@babel/core": "^7.6.0", "@babel/core": "^7.6.0",
@ -71,7 +88,7 @@
"babel-jest": "^24.9.0", "babel-jest": "^24.9.0",
"eslint": "^6.3.0", "eslint": "^6.3.0",
"jest": "^24.9.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" "react-test-renderer": "16.8.6"
}, },
"jest": { "jest": {

View File

@ -2,9 +2,11 @@ import Api from './api'
import { Platform } from 'react-native' import { Platform } from 'react-native'
import Config from 'src/utils/Config' import Config from 'src/utils/Config'
import DeviceInfo from 'react-native-device-info' import DeviceInfo from 'react-native-device-info'
import ApiPowerCondo from "./apiPowerCondo";
import moment from "moment";
export const getUserProfile = () => { export const getUserProfile = () => {
return Api.get('/me'); return Api.get('/mobile/me');
} }
export const testConnect = () => { export const testConnect = () => {
@ -12,7 +14,7 @@ export const testConnect = () => {
} }
export const registerDevice = (pushToken) => { export const registerDevice = (pushToken) => {
return Api.post('/register/device', { return Api.post('/mobile/register/device', {
push_token: pushToken, push_token: pushToken,
uid: DeviceInfo.getUniqueId(), uid: DeviceInfo.getUniqueId(),
brand: DeviceInfo.getBrand(), brand: DeviceInfo.getBrand(),
@ -21,43 +23,56 @@ export const registerDevice = (pushToken) => {
} }
export const register = (user) => { export const register = (user) => {
return Api.post('/register', const formData = new FormData()
user for (let k in user) {
); formData.append(k, user[k])
}
return Api.post('/register', formData );
} }
export const login = (params) => { 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 params
); );
} }
export const logout = () => {
return Api.post('/api/logout');
}
export const dashboard = (params) => { export const dashboard = (params) => {
return Api.get('/me/dashboard'); return Api.get('/mobile/me/dashboard');
} }
export const getNews = (params) => { export const getNews = (params) => {
return Api.get('/news'); return Api.get('/mobile/news');
} }
export const getNewsPage = (page = 1) => { export const getNewsPage = (page = 1) => {
return Api.get('/news?page='+page); return Api.get('/mobile/news?page='+page);
} }
export const getNewsDetail = (news_id) => { export const getNewsDetail = (news_id) => {
return Api.get('/news/'+news_id); return Api.get('/mobile/news/'+news_id);
} }
export const getNewsByProject = (project_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) => { export const project = (keyword) => {
return Api.get('/project'); return Api.get('/mobile/project');
} }
export const getBuildingByProjectId = (project_id) => { 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) => { export const room = (project_id) => {
@ -71,13 +86,13 @@ export const roomdetail = (room_id) => {
} }
export const payment = (user_id) => { export const payment = (user_id) => {
return Api.get('/payment', { return Api.get('/mobile/me/invoice', {
user_id: user_id user_id: user_id
}); });
} }
export const payment_detail = (payments_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) => { export const total_payment = (user_id) => {
@ -85,51 +100,52 @@ export const total_payment = (user_id) => {
} }
export const edit_profile = (user) => { export const edit_profile = (user) => {
const formData = new FormData() // const formData = new FormData()
for (let k in user) { // for (let k in user) {
formData.append(k, user[k]) // formData.append(k, user[k])
} // }
return Api.post('/me/profile', formData ); // let formDataParts = formData._parts ? formData._parts : formData;
return Api.post('/mobile/me/profile', user );
} }
export const get_notification = (user_id, page) => { export const get_notification = (user_id, page) => {
return Api.get('/notification', { return Api.get('/mobile/notification', {
user_id: user_id, user_id: user_id,
page: page page: page
}) })
} }
export const read_notification = (noti_id) => { 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) => { export const count_notification = (user_id) => {
return Api.get('/notification/count', { return Api.get('/mobile/notification/count', {
user_id: user_id user_id: user_id
}) })
} }
export const getSubscription = (customer_id,type) => { export const getSubscription = (customer_id,type) => {
return Api.get('/subscription', { return Api.get('/mobile/subscription', {
customer_id: customer_id, customer_id: customer_id,
type: type, type: type,
}) })
} }
export const postSubscription = (customer_id,type) => { export const postSubscription = (customer_id,type) => {
return Api.post('/subscription', { return Api.post('/mobile/subscription', {
customer_id: customer_id, customer_id: customer_id,
type: type, type: type,
}) })
} }
export const getProductList = () => { export const getProductList = () => {
return Api.get('/product'); return Api.get('/mobile/product');
} }
export const getProductDetail = (product_id) => { export const getProductDetail = (product_id) => {
return Api.get('/product/'+product_id); return Api.get('/mobile/product/'+product_id);
} }
export const getServices = () => { export const getServices = () => {
@ -148,8 +164,8 @@ export const getRepairList = (service_id) => {
return Api.get('/repair'); return Api.get('/repair');
} }
export const getRepairById = (repair_id) => { export const getRepairById = (repair_id, type = '') => {
return Api.get('/repair/'+repair_id); return Api.get(`/repair/${repair_id}?self_room=${(type === 'effect_responsible' ? 'true' : 'false')}`);
} }
export const postRepair = (param) => { export const postRepair = (param) => {
@ -166,7 +182,8 @@ export const postSuggestion = (params) => {
for (let k in params) { for (let k in params) {
formData.append(k, params[k]) 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) => { export const postSuggestionLogin = (params) => {
@ -174,22 +191,22 @@ export const postSuggestionLogin = (params) => {
for (let k in params) { for (let k in params) {
formData.append(k, params[k]) formData.append(k, params[k])
} }
return Api.post('/service_suggestion',formData) return Api.post('/mobile/service-suggestion',formData)
} }
//Question & Answer //Question & Answer
export const getConversation = () => { export const getConversation = () => {
return Api.get('/conversation'); return Api.get('/mobile/conversation');
} }
export const postConversation = (param) => { export const postConversation = (param) => {
return Api.post('/conversation/messages',param); return Api.post('/mobile/conversation/messages',param);
} }
//Object & Message //Object & Message
export const getObjectMessage = () => { export const getObjectMessage = () => {
return Api.get('/parcel'); return Api.get('/mobile/parcel');
} }
export const postSignatureImage = (params) => { export const postSignatureImage = (params) => {
@ -197,29 +214,29 @@ export const postSignatureImage = (params) => {
for (let k in params) { for (let k in params) {
formData.append(k, params[k]) formData.append(k, params[k])
} }
return Api.post('/parcel',formData); return Api.post('/mobile/parcel',formData);
} }
export const getObjectMessageByID = (id) => { export const getObjectMessageByID = (id) => {
return Api.get(`/parcel/${id}`); return Api.get(`/mobile/parcel/${id}`);
} }
//Meter //Meter
export const getMeterList = () => { export const getMeterList = () => {
return Api.get('/meter'); return Api.get('/mobile/meter');
} }
export const getRoomSlideList = (roon_id) => { 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) => { export const postMeter = (params) => {
const formData = new FormData() // const formData = new FormData()
for (let k in params) { // for (let k in params) {
formData.append(k, params[k]) // formData.append(k, params[k])
} // }
return Api.post('/meter',formData); return Api.post('/mobile/meter',params);
} }
export const postMeterImage = (params) => { export const postMeterImage = (params) => {
@ -228,7 +245,7 @@ export const postMeterImage = (params) => {
formData.append(k, params[k]) formData.append(k, params[k])
} }
return Api.post('/ocr',formData); return Api.post('/mobile/ocr',formData);
} }
export const disconnectFacebook = (user) => { export const disconnectFacebook = (user) => {
@ -236,3 +253,126 @@ export const disconnectFacebook = (user) => {
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 { create } from 'apisauce'
import Config from 'src/utils/Config' import Config from 'src/utils/Config'
import DeviceInfo from 'react-native-device-info' import DeviceInfo from 'react-native-device-info'
import { Alert, NetInfo, Platform } from 'react-native' import { Alert, Platform } from 'react-native'
import NavigationService from 'src/utils/NavigationService'
// import { strings as t } from '../i18n' // import { strings as t } from '../i18n'
// import { userLogout } from 'src/redux/app/action' // import { userLogout } from 'src/redux/app/action'
@ -11,15 +10,26 @@ import NavigationService from 'src/utils/NavigationService'
let store let store
const Api = create({ const Api = create({
baseURL: Config.API_BASE_URL, // baseURL: Config.API_BASE_URL_PROD,
baseURL: Config.API_BASE_URL_POWER_CONDO_DEV,
headers: { headers: {
'X-Frame-Options': 'sameorigin', 'X-Frame-Options': 'sameorigin',
'X-App-Version': DeviceInfo.getVersion(), 'X-App-Version': DeviceInfo.getVersion(),
'X-Device-OS': Platform.OS, 'X-Device-OS': Platform.OS,
'X-Device-Version': Platform.Version, '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 => { DeviceInfo.getDeviceName().then(name => {
Api.setHeader('X-Device-Name', name) Api.setHeader('X-Device-Name', name)
}) })
@ -29,11 +39,11 @@ Api.addRequestTransform(request => {
}) })
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
Api.addRequestTransform(request => { Api.addRequestTransform(request => {
console.info('--> [' + request.method + '] ' + Api.getBaseURL() + request.url,request.params, request.data) console.info('--> [' + request.method + '] ' + Api.getBaseURL() + request.url, request.params, request.data)
console.info('header --' + request.url +' -- ', request.headers) console.info('header --' + request.url + ' -- ', request.headers)
}) })
Api.addMonitor(response => { 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 'SERVER_ERROR':
case 'CANCEL_ERROR': case 'CANCEL_ERROR':
case 'CLIENT_ERROR': // 4XX case 'CLIENT_ERROR': // 4XX
if (response.status === 401) { /*if (response.status === 401) {
// store.dispatch(userLogout)
Alert.alert('Session timeout', 'Please login again to continue using application', [ Alert.alert('Session timeout', 'Please login again to continue using application', [
{ {
text: 'ok', text: 'ok',
@ -58,20 +67,20 @@ Api.addMonitor(response => {
// NavigationService.navigate('AppLoading') // NavigationService.navigate('AppLoading')
} }
} }
], {cancelable: false}) ], { cancelable: false })
return return
} }*/
// Alert.alert(null, 'error_getting_data', [{text: 'ok'}]) // Alert.alert(null, 'error_getting_data', [{text: 'ok'}])
break break
} }
} }
}) })
export function setStore(reduxStore) { export function setStore (reduxStore) {
store = reduxStore store = reduxStore
} }
export function setToken(token) { export function setToken (token) {
Api.setHeader('Authorization', 'Bearer ' + token) Api.setHeader('Authorization', 'Bearer ' + token)
} }
@ -79,13 +88,13 @@ export function setLanguage (languageCode) {
Api.setHeader('language', languageCode) Api.setHeader('language', languageCode)
} }
export function clearToken() { export function clearToken () {
Api.deleteHeader('Authorization') 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-Latitude', lat.toString() || '0.0')
Api.setHeader('X-Current-Longitude', lng.toString() || '0.0') Api.setHeader('X-Current-Longitude', lng.toString() || '0.0')
} }
export default Api export default Api

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

View File

@ -5,6 +5,7 @@ import { login, disconnectFacebook } from '../api/UserApi'
import { store } from '../redux/store' import { store } from '../redux/store'
import { Alert } from 'react-native' import { Alert } from 'react-native'
import NavigationService from '../utils/NavigationService'; import NavigationService from '../utils/NavigationService';
import messaging from "@react-native-firebase/messaging";
let requestManager = new GraphRequestManager(); 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 = { let params = {
access_token: accessToken, access_token: accessToken,
fcm_token: fcmToken
} }
login(params) login(params)
.then(async (res) => { .then(async (res) => {
if(res.status == 500){ if(res.status == 500){
@ -66,13 +79,15 @@ export function logoutFacebook() {
export function disconnectWithFacebook(onSuccess){ export function disconnectWithFacebook(onSuccess){
AccessToken.getCurrentAccessToken()
AccessToken.getCurrentAccessToken().then( .then((data) => {
(data) => {
console.log("AccessToken.getCurrentAccessToken():") console.log("AccessToken.getCurrentAccessToken():")
console.log(data) 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:")
//console.log(accessToken) //console.log(accessToken)
@ -91,20 +106,7 @@ export function disconnectWithFacebook(onSuccess){
} }
if (res.ok) { if (res.ok) {
Alert.alert('Disconnect with Facebook Success') onSuccess && onSuccess();
// 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()
// }
} else { } else {
if(res.data.msg != null){ if(res.data.msg != null){
Alert.alert('',res.data.msg) 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>
);
}
}

View File

@ -1,7 +1,7 @@
import React from 'react' import React, {useCallback, useRef, useState} from 'react'
import { TouchableOpacity, View, StyleSheet } from 'react-native' import {Modal, StyleSheet, TouchableOpacity, View} from 'react-native'
import Image from 'react-native-fast-image' import Image from 'react-native-fast-image'
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation' import {createBottomTabNavigator, createStackNavigator} from 'react-navigation'
import NewsScreen from '../screens/news/News' import NewsScreen from '../screens/news/News'
import RoomScreen from '../screens/room/Room' import RoomScreen from '../screens/room/Room'
import ProductScreen from '../screens/product/Product' import ProductScreen from '../screens/product/Product'
@ -19,33 +19,50 @@ import Icon from 'src/components/Icon'
import PersonRoomReservationScreen from '../screens/room/PersonRoomReservation' import PersonRoomReservationScreen from '../screens/room/PersonRoomReservation'
import CompanyRoomReservationScreen from '../screens/room/CompanyRoomReservation' import CompanyRoomReservationScreen from '../screens/room/CompanyRoomReservation'
import RoomHeaderReservationScreen from '../screens/room/RoomHeaderReservation' import RoomHeaderReservationScreen from '../screens/room/RoomHeaderReservation'
import Text from 'src/components/Text'; import Text from 'src/components/Text'
import { news } from '../api/UserApi'; import {bindActionCreators} from 'redux'
import { bindActionCreators } from 'redux' import {appCleanUser, appSetNotification, setServerMode} from '../redux/app/action'
import { appSetNotification } from '../redux/app/action' import {connect, useDispatch, useSelector} from 'react-redux'
import { connect } from 'react-redux' import PaymentScreen from '../screens/bill/Payment'
import PaymentScreen from "../screens/bill/Payment"; import MessageObject from '../screens/object/MessageObject'
import MessageObject from '../screens/object/MessageObject'; import MessageObjectDetail from '../screens/object/MessageObjectDetail'
import MessageObjectDetail from '../screens/object/MessageObjectDetail';
import RegisterScreen from '../screens/login/Register' import RegisterScreen from '../screens/login/Register'
import RegisterProfileScreen from '../screens/login/RegisterProfile' import RegisterProfileScreen from '../screens/login/RegisterProfile'
import RegisterFormLoginScreen from '../screens/login/RegisterFormLogin' import RegisterFormLoginScreen from '../screens/login/RegisterFormLogin'
import LoginScreen from '../screens/login/Login' import LoginScreen from '../screens/login/Login'
import SignaturePadScreen from '../screens/object/SignaturePadScreen'; import SignaturePadScreen from '../screens/object/SignaturePadScreen'
import WaterMeter from '../screens/meters/WaterMeter'; import WaterMeter from '../screens/meters/WaterMeter'
import PEAMeter from '../screens/meters/PEAMeter'; import PEAMeter from '../screens/meters/PEAMeter'
import ZoneAreaScreen from '../screens/room/ZoneAreaScreen'; import ZoneAreaScreen from '../screens/room/ZoneAreaScreen'
import RepairServiceDetail from '../screens/repair/RepairServiceDetail'; import RepairServiceDetail from '../screens/repair/RepairServiceDetail'
import RepairService from '../screens/repair/RepairService'; import RepairService from '../screens/repair/RepairService'
import RepairConfirm from '../screens/repair/RepairConfirm'; import RepairIndex from '../screens/repair/RepairIndex'
import RepairHistory from '../screens/repair/RepairHistory'; import RepairConfirm from '../screens/repair/RepairConfirm'
import RepairSuccess from '../screens/repair/RepairSuccess'; import RepairHistory from '../screens/repair/RepairHistory'
import RepairHistoryDetail from '../screens/repair/RepairHistoryDetail'; import RepairSuccess from '../screens/repair/RepairSuccess'
import RewardScreen from '../screens/reward/RewardScreen'; import RepairHistoryDetail from '../screens/repair/RepairHistoryDetail'
import RewardDetailScreen from '../screens/reward/RewardDetailScreen'; import RewardScreen from '../screens/reward/RewardScreen'
import QuestionScreen from '../screens/service/QuestionScreen'; import RewardDetailScreen from '../screens/reward/RewardDetailScreen'
import QuestionScreen from '../screens/service/QuestionScreen'
import TermsAndCondition from '../screens/login/TermsAndCondition' import TermsAndCondition from '../screens/login/TermsAndCondition'
import { locale, t } from 'src/utils/i18n' import MoveOutScreen from "../screens/service/MoveOutScreen";
import RoomReservation from "../screens/room/RoomReservationWebView";
import {locale, t} from 'src/utils/i18n'
import {store} from 'src/redux/store'
import RedeemScreen from "../screens/redeem/RedeemScreen";
import HistoryRedeem from "../screens/redeem/HistoryRedeem";
import AllRewards from "../screens/redeem/AllRewards";
import MyRewards from "../screens/redeem/MyRewards";
import RewardDetail from "../screens/redeem/RewardDetail";
import RewardTermCondition from "../screens/redeem/RewardTermCondition"
import ScanCoupon from "../screens/redeem/ScanCoupon";
import ForgetPasswordScreen from '../screens/forget_password/ForgetPasswordScreen'
import VerifyOTP from '../screens/forget_password/VerifyOTP'
import PasswordCode from '../screens/forget_password/PasswordCode'
import PaymentDetail from '../screens/bill/PaymentDetail'
import PaymentConfirm from '../screens/bill/PaymentConfirm'
import MembershipLevelDetail from '../screens/redeem/MembershipLeveDetail'
import MemberPoinExpire from '../screens/redeem/MemberPoinExpire'
const screenConfig = (screen, title, backgroundColor = undefined) => ({ const screenConfig = (screen, title, backgroundColor = undefined) => ({
screen, screen,
@ -86,11 +103,11 @@ const NavWithRightIcon = (title, iconName, routeName) => ({ navigation }) => ({
<TouchableOpacity <TouchableOpacity
style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }} style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }}
onPress={() => navigation.goBack()}> onPress={() => navigation.goBack()}>
<Icon name="ic_back" size={20} color="#fff" /> <Icon name="ic_back" size={20} color="#fff"/>
</TouchableOpacity> </TouchableOpacity>
), ),
headerRight: ( headerRight: (
<TouchableOpacity style={{paddingRight:16}} onPress={() => {navigation.navigate(routeName)}}> <TouchableOpacity style={{ paddingRight: 16 }} onPress={() => {navigation.navigate(routeName)}}>
<Icon name={iconName} color={'white'} size={20}/> <Icon name={iconName} color={'white'} size={20}/>
</TouchableOpacity> </TouchableOpacity>
) )
@ -101,6 +118,7 @@ const defaultNavOption = (title, backgroundColor) => ({ navigation }) => ({
headerStyle: { headerStyle: {
backgroundColor: backgroundColor || '#00420A', backgroundColor: backgroundColor || '#00420A',
height: 50, height: 50,
marginTop: 25,
elevation: 0, elevation: 0,
shadowOpacity: 0, shadowOpacity: 0,
}, },
@ -130,7 +148,7 @@ const defaultNavOption = (title, backgroundColor) => ({ navigation }) => ({
<TouchableOpacity <TouchableOpacity
style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }} style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }}
onPress={() => navigation.goBack()}> onPress={() => navigation.goBack()}>
<Icon name="ic_back" size={20} color="#fff" /> <Icon name="ic_back" size={20} color="#fff"/>
</TouchableOpacity> </TouchableOpacity>
), ),
headerRight: ( headerRight: (
@ -141,104 +159,104 @@ const defaultNavOption = (title, backgroundColor) => ({ navigation }) => ({
}) })
const BottomTab = createBottomTabNavigator({ const BottomTab = createBottomTabNavigator({
HomeScreen: { HomeScreen: {
screen: NewsScreen, screen: NewsScreen,
navigationOptions: ({ navigation }) => ({ navigationOptions: ({ navigation }) => ({
tabBarVisible: true, tabBarVisible: true,
tabBarLabel: ({ focused, tintColor }) => { tabBarLabel: ({ focused, tintColor }) => {
if (focused) { if (focused) {
tintColor = '#FFCC00' tintColor = '#FFCC00'
} else { } else {
tintColor = 'rgba(255, 255, 255, 0.65)' tintColor = 'rgba(255, 255, 255, 0.65)'
} }
return <View style={{justifyContent:'center',alignItems:'center'}}> return <View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Icon name={'ic_newspaper'} size={20} color={tintColor} /> <Icon name={'ic_newspaper'} size={20} color={tintColor}/>
<Text style={[styles.textBottomTab,{color: tintColor}]}>{t('news')}</Text> <Text style={[styles.textBottomTab, { color: tintColor }]}>{t('news')}</Text>
</View> /* 'Room' */ </View> /* 'Room' */
}, },
tabBarIcon: ({ focused, tintColor }) => { tabBarIcon: ({ focused, tintColor }) => {
if (focused) { if (focused) {
tintColor = '#FFCC00' tintColor = '#FFCC00'
} else { } else {
tintColor = 'rgba(255, 255, 255, 0.65)' tintColor = 'rgba(255, 255, 255, 0.65)'
}
return <View></View>
} }
return <View></View> })
} },
}) RoomScreen: {
}, // screen: ZoneAreaScreen,
RoomScreen: { screen: RoomReservation,
screen: ZoneAreaScreen, navigationOptions: ({ navigation }) => ({
// screen: RoomScreen, tabBarLabel: ({ focused, tintColor }) => {
navigationOptions: ({ navigation }) => ({ if (focused) {
tabBarLabel: ({ focused, tintColor }) => { tintColor = '#FFCC00'
if (focused) { } else {
tintColor = '#FFCC00' tintColor = 'rgba(255, 255, 255, 0.65)'
} else { }
tintColor = 'rgba(255, 255, 255, 0.65)' return <View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Icon name={'ic_bed-outline'} size={22} color={tintColor}/>
<Text style={[styles.textBottomTab, { color: tintColor }]}>{t('room')}</Text>
</View> /* 'Room' */
},
tabBarIcon: ({ focused, tintColor }) => {
if (focused) {
tintColor = '#FFCC00'
} else {
tintColor = 'rgba(255, 255, 255, 0.65)'
}
} }
return <View style={{justifyContent:'center',alignItems:'center'}}> })
<Icon name={'ic_bed-outline'} size={22} color={tintColor} /> },
<Text style={[styles.textBottomTab,{color: tintColor}]}>{t('room')}</Text> FavorsScreen: {
</View> /* 'Room' */ screen: RewardScreen,
}, navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => { tabBarLabel: ({ focused, tintColor }) => {
if (focused) { if (focused) {
tintColor = '#FFCC00' tintColor = '#FFCC00'
} else { } else {
tintColor = 'rgba(255, 255, 255, 0.65)' tintColor = 'rgba(255, 255, 255, 0.65)'
} }
} return <View style={{ justifyContent: 'center', alignItems: 'center' }}>
}) <Icon name={'ic_star_sq'} size={20} color={tintColor}/>
}, <Text style={[styles.textBottomTab, { color: tintColor }]}>{t('products')}</Text>
FavorsScreen: { </View> /* 'Favaors' */
screen: RewardScreen, },
navigationOptions: ({ navigation }) => ({ tabBarIcon: ({ focused, tintColor }) => {
tabBarLabel: ({ focused, tintColor }) => { if (focused) {
if (focused) { tintColor = '#FFCC00'
tintColor = '#FFCC00' } else {
} else { tintColor = 'rgba(255, 255, 255, 0.65)'
tintColor = 'rgba(255, 255, 255, 0.65)' }
}
return <View style={{justifyContent:'center',alignItems:'center'}}>
<Icon name={'ic_star_sq'} size={20} color={tintColor} />
<Text style={[styles.textBottomTab,{color: tintColor}]}>{t('products')}</Text>
</View> /* 'Favaors' */
},
tabBarIcon: ({ focused, tintColor }) => {
if (focused) {
tintColor = '#FFCC00'
} else {
tintColor = 'rgba(255, 255, 255, 0.65)'
}
}
})
},
ServiceScreen: {
screen: ServiceScreen/* ServiceScreen */,
navigationOptions: ({ navigation }) => ({
tabBarLabel: ({ focused, tintColor }) => {
if (focused) {
tintColor = '#FFCC00'
} else {
tintColor = 'rgba(255, 255, 255, 0.65)'
} }
})
},
ServiceScreen: {
screen: ServiceScreen/* ServiceScreen */,
navigationOptions: ({ navigation }) => ({
tabBarLabel: ({ focused, tintColor }) => {
if (focused) {
tintColor = '#FFCC00'
} else {
tintColor = 'rgba(255, 255, 255, 0.65)'
}
return <View style={{justifyContent:'center',alignItems:'center'}}> return <View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Icon name={'ic_grid'} size={20} color={tintColor} /> <Icon name={'ic_grid'} size={20} color={tintColor}/>
<Text style={[styles.textBottomTab,{color: tintColor}]}>{t('service')}</Text> <Text style={[styles.textBottomTab, { color: tintColor }]}>{t('service')}</Text>
</View> /* 'Room' */ </View> /* 'Room' */
}, },
tabBarIcon: ({ focused, tintColor }) => { tabBarIcon: ({ focused, tintColor }) => {
if (focused) { if (focused) {
tintColor = '#FFCC00' tintColor = '#FFCC00'
} else { } else {
tintColor = 'rgba(255, 255, 255, 0.65)' tintColor = 'rgba(255, 255, 255, 0.65)'
}
} }
} })
}) }
} },
},
{ {
tabBarOptions: { tabBarOptions: {
activeTintColor: '#FFCC00', activeTintColor: '#FFCC00',
@ -246,72 +264,157 @@ const BottomTab = createBottomTabNavigator({
} }
}) })
//export default LoginScreen //export default LoginScreen
const mapDisPatchToProps = state => { const mapDisPatchToProps = state => {
return state.app return state.app
}
const setNotification = dispatch => bindActionCreators({ appSetNotification }, dispatch)
const NotificationIcon = connect(mapDisPatchToProps, setNotification)(({ count_noti, user }) => {
let count = 0
if (count_noti) {
count = count_noti
} }
const setNotification = dispatch => bindActionCreators({ appSetNotification }, dispatch) if (count > 0) {
const NotificationIcon = connect(mapDisPatchToProps, setNotification)(({count_noti,user}) => { return <View>
let count = 0; <View
if(count_noti){ style={{
count = count_noti width: 16,
} height: 16,
if(count > 0){ backgroundColor: '#FF2D55',
return <View> borderRadius: 50,
<View justifyContent: 'center',
style={{ alignItems: 'center',
width: 16, position: 'absolute',
height: 16, right: '10%',
backgroundColor: '#FF2D55', top: '-10%',
borderRadius: 50, zIndex: 1,
justifyContent: 'center', roomLength: 0
alignItems: 'center', }}>
position: 'absolute', <Text style={{ color: 'white', fontSize: 8 }}>{count && count > 9 ? '9+' : count}</Text>
right: '10%', </View>
top: '-10%', <View style={{ marginRight: 10 }}>
zIndex: 1 <Icon name={'ic_bell'} size={20} color={'white'}/>
}}> </View>
<Text style={{ color: 'white', fontSize: 8 }}>{count && count > 9 ? '9+' : count }</Text> </View>
</View> } else {
return (
<View>
<View style={{ marginRight: 10 }}> <View style={{ marginRight: 10 }}>
<Icon name={'ic_bell'} size={20} color={'white'} /> <Icon name={'ic_bell'} size={20} color={'white'}/>
</View> </View>
</View>; </View>
}else{ )
return ( }
<View>
<View style={{ marginRight: 10 }}>
<Icon name={'ic_bell'} size={20} color={'white'} />
</View>
</View>
)
}
}) })
const MainTitle = connect(state => ({ const MainTitle = connect(state => ({
user: state.app.user, user: state.app.user,
state_app: state.app,
}))((props) => { }))((props) => {
let userText = ''; let userText = ''
let room = ''; let room = ''
let name = ''; let roomPopup = ''
console.log("props.user.", props.user); let name = ''
if(props.user && typeof props.user.room != 'undefined'){ let projectName = ''
room = " "+props.user.room; console.log('props.user.', props.user)
console.log('props.state_app:', props.state_app)
if (props.user && typeof props.user.room != 'undefined') {
room = ' ' + props.user.room
roomPopup = props.user.room
// console.log('room',room)
if (room.length >= 16) {
room = room.substring(0, 16) + '...'
} }
if(props.user && typeof props.user.name != 'undefined'){
name = props.user.name.split(" ");
}
if (props.user) {
userText = `(${name[0]}${room})`
} }
return <Text style={{ fontSize: 18, color: '#FFFFFF', marginLeft: 15, marginTop: 3 }}>{t('charoensin_asset')} {userText} </Text>
if (props.user && typeof props.user.name != 'undefined') {
name = props.user.name.split(' ')
}
if (props.user) {
userText = `${name[0]}`;
projectName = props.user.project_name
}
return <View>
<Text style={{ fontSize: 16, color: '#FFFFFF', marginLeft: 10, marginTop: 3, marginBottom: 5 }}>{t('charoensin_asset')} {projectName}</Text>
</View>
}) })
const MainHeader = ({ navigation }) => {
const lastCount = useRef(0)
const counter = useRef(0)
const [showModal, setShowModal] = useState(false)
const dispatch = useDispatch()
const server_mode = useSelector(state => state.app.server_mode)
const openSecretChamber = useCallback(() => {
const t = new Date().getTime()
if (t - lastCount.current < 500) {
if (++counter.current >= 10) {
setShowModal(true)
}
} else {
counter.current = 1
}
lastCount.current = t
}, [])
const changeServer = useCallback((mode) => {
dispatch(setServerMode(mode))
setShowModal(false)
}, [])
return <View style={[{ flex: 1, alignItems: 'center', flexDirection: 'row', marginTop: 0, paddingLeft: 10, backgroundColor: server_mode === 'develop' ? '#ff0000' : 'transparent' }]}>
<TouchableOpacity
onPress={openSecretChamber}
activeOpacity={1}>
<Image
style={{ width: 35, height: 35, }}
source={require('../../assets/images/logo_white_border.png')}
/>
</TouchableOpacity>
<MainTitle/>
<Modal transparent={true} visible={showModal}>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<View style={{ backgroundColor: 'white', padding: 20, borderRadius: 10 }}>
<View>
<Text>งค Server</Text>
</View>
<View style={{ marginTop: 10 }}>
<TouchableOpacity style={{ padding: 10 }} onPress={() => changeServer('production')}>
<Text style={{ color: server_mode == 'production' ? '#004287' : '#aaa' }}>PRODUCTION</Text>
</TouchableOpacity>
<TouchableOpacity style={{ padding: 10 }} onPress={() => changeServer('develop')}>
<Text style={{ color: server_mode == 'develop' ? '#004287' : '#aaa' }}>DEVELOP</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
</View>
}
const HeaderLeftComponent = (navigation, routeName = null, propsRoute = null) => {
return (
<TouchableOpacity
style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }}
onPress={() => routeName ? navigation.navigate(routeName, propsRoute || null) : navigation.goBack()}>
<Icon name="ic_back" size={20} color="#fff"/>
</TouchableOpacity>
)
}
const defaultHeaderStyle = () => {
return {
headerStyle: styles.defaultHeaderStyle,
headerTintColor: '#000',
headerTitleStyle: styles.defaultHeaderTitleStyle,
headerTitleContainerStyle: styles.defaultHeaderTitleContainerStyle,
headerLeftContainerStyle: styles.defaultHeaderLeftContainerStyle,
headerTitleAllowFontScaling: false,
}
}
const AppStack = createStackNavigator({ const AppStack = createStackNavigator({
BottomTab: { BottomTab: {
screen: BottomTab, screen: BottomTab,
navigationOptions: ({ navigation }) => { navigationOptions: ({navigation}) => {
let langIcon let langIcon
switch (locale()) { switch (locale()) {
case 'th': case 'th':
@ -332,6 +435,7 @@ const AppStack = createStackNavigator({
headerStyle: { headerStyle: {
backgroundColor: '#00420A', backgroundColor: '#00420A',
height: 50, height: 50,
marginTop: 25,
elevation: 0, elevation: 0,
shadowOpacity: 0, shadowOpacity: 0,
}, },
@ -344,31 +448,23 @@ const AppStack = createStackNavigator({
marginLeft: 30, marginLeft: 30,
}, },
headerRight: ( headerRight: (
<View style={{ marginRight: 0, justifyContent: 'center', alignItems: 'center', flexDirection: 'row' }}> <View style={{marginRight: 0, justifyContent: 'center', alignItems: 'center', flexDirection: 'row'}}>
<TouchableOpacity onPress={() => navigation.navigate('LanguageSelect')} style={{marginRight:8}}> <TouchableOpacity onPress={() => navigation.navigate('LanguageSelect')} style={{marginRight: 8}}>
<View style={{ width: 30, height: 30, alignItems: 'center', justifyContent: 'center' }}> <View style={{width: 30, height: 30, alignItems: 'center', justifyContent: 'center'}}>
<Image style={{width:25,height:25}} source={langIcon}/></View> <Image style={{width: 25, height: 25}} source={langIcon}/></View>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={{ marginRight: 6 }} onPress={() => navigation.navigate('Notification')}> <TouchableOpacity style={{marginRight: 6}} onPress={() => navigation.navigate('Notification')}>
<NotificationIcon/> <NotificationIcon/>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
), ),
headerLeftContainerStyle: { headerLeftContainerStyle: {
width:'80%', width: '80%',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
}, },
headerLeft: ( headerLeft: () => <MainHeader navigation={navigation}/>,
<View style={[{ flex: 1, flexDirection: 'row', marginTop: 0, paddingLeft: 10 }]}> }
<Image
style={{ width: 35, height: 35, }}
source={require('../../assets/images/logo_white_border.png')}
/>
<MainTitle/>
</View>
),
};
} }
@ -381,7 +477,7 @@ const AppStack = createStackNavigator({
RoomHeaderReservation: screenConfig(RoomHeaderReservationScreen, 'book_room'), RoomHeaderReservation: screenConfig(RoomHeaderReservationScreen, 'book_room'),
News: { News: {
screen: NewsScreen, screen: NewsScreen,
navigationOptions: ({ navigation }) => ({ navigationOptions: ({navigation}) => ({
title: t('charoensin_asset'), title: t('charoensin_asset'),
headerLeft: ( headerLeft: (
<TouchableOpacity onPress={() => navigation.goBack()}> <TouchableOpacity onPress={() => navigation.goBack()}>
@ -392,11 +488,12 @@ const AppStack = createStackNavigator({
}, },
NewsDetail: { NewsDetail: {
screen: NewsDetailScreen, screen: NewsDetailScreen,
navigationOptions: ({ navigation }) => ({ navigationOptions: ({navigation}) => ({
title: '', title: '',
headerStyle: { headerStyle: {
backgroundColor: '#00420A', backgroundColor: '#00420A',
height: 50, height: 50,
marginTop: 25,
elevation: 0, elevation: 0,
shadowOpacity: 0, shadowOpacity: 0,
}, },
@ -410,14 +507,14 @@ const AppStack = createStackNavigator({
headerLeft: null, headerLeft: null,
headerRight: ( headerRight: (
<TouchableOpacity onPress={() => navigation.goBack()}> <TouchableOpacity onPress={() => navigation.goBack()}>
<Text style={{ color: '#fff', fontSize: 16 }}> {t('close')} </Text> <Text style={{color: '#fff', fontSize: 16}}> {t('close')} </Text>
</TouchableOpacity> </TouchableOpacity>
) )
}) })
}, },
Product: { Product: {
screen: ProductScreen, screen: ProductScreen,
navigationOptions: ({ navigation }) => ({ navigationOptions: ({navigation}) => ({
title: t('products'), title: t('products'),
headerLeft: ( headerLeft: (
<TouchableOpacity onPress={() => navigation.goBack()}> <TouchableOpacity onPress={() => navigation.goBack()}>
@ -440,39 +537,46 @@ const AppStack = createStackNavigator({
// } // }
, ,
Meter: screenConfig(MeterScreen, 'smart_meter'), Meter: screenConfig(MeterScreen, 'smart_meter'),
WaterMeter: screenConfig(WaterMeter,'save_water_meter'), WaterMeter: screenConfig(WaterMeter, 'save_water_meter'),
PEAMeter: screenConfig(PEAMeter,'save_electric_meter'), PEAMeter: screenConfig(PEAMeter, 'save_electric_meter'),
// Bill: screenConfig(BillScreen, 'รายละเอียดยอดค้างชำระ'), // Bill: screenConfig(BillScreen, 'รายละเอียดยอดค้างชำระ'),
Bill: screenConfig(BillScreen,'outstanding_balance_detail'), Bill: screenConfig(BillScreen, 'outstanding_balance_detail'),
Payment: screenConfig(PaymentScreen, 'pay'), Payment: screenConfig(PaymentScreen, 'pay'),
PaymentDetail: screenConfig(PaymentDetail, 'payment_detail'),
PaymentConfirm: screenConfig(PaymentConfirm, 'payment_detail'),
SettingsNotification: screenConfig(SettingsNotificationScreen, 'noti_setting'), SettingsNotification: screenConfig(SettingsNotificationScreen, 'noti_setting'),
MoveOut: screenConfig(MoveOutScreen, 'move_out'),
Suggestion: screenConfig(SuggestionScreen, 'suggestion'), Suggestion: screenConfig(SuggestionScreen, 'suggestion'),
Question: { Question: {
screen: QuestionScreen, screen: QuestionScreen,
navigationOptions: ({ navigation }) => ({ navigationOptions: ({navigation}) => ({
title: t('faqs'), title: t('faqs'),
headerStyle:{ headerStyle: {
backgroundColor: '#00420A', backgroundColor: '#00420A',
marginTop: 25,
height: 50
}, },
headerTitleStyle: { headerTitleStyle: {
fontSize: 18, fontSize: 18,
color: '#fff', color: '#fff',
fontFamily: 'Prompt-Regular', fontFamily: 'Prompt-Regular',
fontWeight: undefined, fontWeight: undefined,
}, headerLeftContainerStyle: { textAlign: 'left',
flex: 1,
marginLeft: 0
}, headerLeftContainerStyle: {
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
width: '10%', width: '10%',
}, },
headerLeft: ( headerLeft: (
<TouchableOpacity onPress={() => navigation.goBack()} style={{flex:1,alignItems:'center'}}> <TouchableOpacity onPress={() => navigation.goBack()} style={{flex: 1, alignItems: 'center'}}>
<Icon name={'ic_back'} color={'white'} size={20}/> <Icon name={'ic_back'} color={'white'} size={20}/>
</TouchableOpacity> </TouchableOpacity>
), ),
headerRight:( headerRight: (
<TouchableOpacity onPress={() => navigation.state.params.onRefreshMessage()} style={{paddingRight:16}}> <TouchableOpacity onPress={() => navigation.state.params.onRefreshMessage()} style={{paddingRight: 16}}>
<Icon name={'ic_refresh'} color={'white'} size={20}/> <Icon name={'ic_refresh'} color={'white'} size={20}/>
</TouchableOpacity> </TouchableOpacity>
) )
@ -480,15 +584,58 @@ const AppStack = createStackNavigator({
}, },
Profile: screenConfig(ProfileScreen, 'profile', '#3AA40C'), Profile: screenConfig(ProfileScreen, 'profile', '#3AA40C'),
EditProfile: screenConfig(EditProfileScreen, 'edit_profile', '#3AA40C'), EditProfile: screenConfig(EditProfileScreen, 'edit_profile', '#3AA40C'),
Object: screenConfig(MessageObject, 'mail_and_parcel'), Object: {
screen: MessageObject,
navigationOptions: ({navigation}) => ({
title: t('mail_and_parcel'),
headerStyle: {
backgroundColor: '#00420A',
height: 50,
marginTop: 25,
elevation: 0,
shadowOpacity: 0,
},
headerTintColor: '#000',
headerTitleStyle: {
fontWeight: '400',
fontSize: 18,
color: '#fff',
textAlign: 'left',
flex: 1,
fontFamily: 'Prompt-Regular',
marginLeft: 0,
},
headerTitleContainerStyle: {
alignItems: 'center',
justifyContent: 'center',
},
headerLeftContainerStyle: {
alignItems: 'center',
justifyContent: 'center',
width: '10%',
},
headerTitleAllowFontScaling: false,
headerLeft: (
<TouchableOpacity
style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }}
onPress={() => navigation.navigate('HomeScreen')}>
<Icon name="ic_back" size={20} color="#fff"/>
</TouchableOpacity>
)
})
},
ObjectDetail: screenConfig(MessageObjectDetail, 'mail_and_parcel'), ObjectDetail: screenConfig(MessageObjectDetail, 'mail_and_parcel'),
Signature: screenConfig(SignaturePadScreen, 'please_sign'), Signature: screenConfig(SignaturePadScreen, 'please_sign'),
Login: { Login: {
screen: LoginScreen, screen: LoginScreen,
navigationOptions: ({ navigation }) => ({ navigationOptions: ({navigation}) => ({
title: t('login'), title: t('login'),
headerStyle:{ headerStyle: {
backgroundColor: '#00420A', backgroundColor: '#00420A',
marginTop: 25,
height: 50
}, },
headerTitleStyle: { headerTitleStyle: {
@ -496,7 +643,7 @@ const AppStack = createStackNavigator({
color: '#fff', color: '#fff',
fontFamily: 'Prompt-Regular', fontFamily: 'Prompt-Regular',
fontWeight: undefined, fontWeight: undefined,
}, headerLeftContainerStyle: { }, headerLeftContainerStyle: {
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
width: '10%', width: '10%',
@ -509,32 +656,200 @@ const AppStack = createStackNavigator({
) )
}) })
}, },
//Forget Password Screen
ForgetPassword: {
screen: ForgetPasswordScreen,
navigationOptions: ({navigation}) => ({
title: t('forget_password'),
headerStyle: styles.defaultHeaderStyle,
headerTitleStyle: {
...styles.defaultHeaderTitleStyle,
fontWeight: undefined,
},
headerLeftContainerStyle: styles.defaultHeaderLeftContainerStyle,
headerLeft: (
<TouchableOpacity onPress={() => navigation.navigate('HomeScreen')}>
<Icon name={'ic_back'} color={'white'} size={20}/>
</TouchableOpacity>
)
})
},
VerifyOTP: {
screen: VerifyOTP,
navigationOptions: ({navigation}) => ({
title: t('verify_otp'),
headerStyle: styles.defaultHeaderStyle,
headerTitleStyle: {
...styles.defaultHeaderTitleStyle,
fontWeight: undefined,
},
headerLeftContainerStyle: styles.defaultHeaderLeftContainerStyle,
headerLeft: (
<TouchableOpacity onPress={() => navigation.navigate('ForgetPassword')}>
<Icon name={'ic_back'} color={'white'} size={20}/>
</TouchableOpacity>
)
})
},
PasswordCode: {
screen: PasswordCode,
navigationOptions: ({navigation}) => ({
title: t('new_password'),
headerStyle: styles.defaultHeaderStyle,
headerTitleStyle: {
...styles.defaultHeaderTitleStyle,
fontWeight: undefined,
},
headerLeftContainerStyle: styles.defaultHeaderLeftContainerStyle,
headerLeft: (
<TouchableOpacity onPress={() => navigation.navigate('VerifyOTP')}>
<Icon name={'ic_back'} color={'white'} size={20}/>
</TouchableOpacity>
)
})
},
//Register Screen //Register Screen
Register: screenConfig(RegisterScreen,'register'), Register: screenConfig(RegisterScreen, 'register'),
RegisterFormLogin: screenConfig(RegisterFormLoginScreen, 'register'), RegisterFormLogin: screenConfig(RegisterFormLoginScreen, 'register'),
RegisterProfile: screenConfig(RegisterProfileScreen, 'register'), RegisterProfile: screenConfig(RegisterProfileScreen, 'register'),
//Repair Service //Repair Service
RepairService: { /*RepairService: {
screen: RepairService, screen: RepairService,
navigationOptions: NavWithRightIcon('request_repair_and_Other','ic_clock_history','RepairHistory') navigationOptions: NavWithRightIcon('request_repair_and_Other', 'ic_clock_history', 'RepairHistory')
}, },*/
RepairDetail: screenConfig(RepairServiceDetail,'service_detail'), Repair: screenConfig(RepairIndex, 'request_repair'),
RepairDetail: screenConfig(RepairServiceDetail, 'service_detail'),
RepairConfirm: screenConfig(RepairConfirm, 'confirm_info'), RepairConfirm: screenConfig(RepairConfirm, 'confirm_info'),
RepairHistory: screenConfig(RepairHistory, 'repair_history'), RepairHistory: screenConfig(RepairHistory, 'repair_history'),
RepairSuccess: screenConfig(RepairSuccess, 'request_sent'), RepairSuccess: screenConfig(RepairSuccess, 'request_sent'),
RepairHistoryDetail: screenConfig(RepairHistoryDetail, 'รายละเอียดประวัติ'), // RepairHistoryDetail: screenConfig(RepairHistoryDetail, 'repair_history_detail'),
RepairHistoryDetail: {
screen: RepairHistoryDetail,
navigationOptions: ({navigation}) => ({
title: t('repair_history_detail'),
headerStyle: {
backgroundColor: '#00420A',
height: 50,
elevation: 0,
shadowOpacity: 0,
},
headerTintColor: '#000',
headerTitleStyle: {
fontWeight: '400',
fontSize: 18,
color: '#fff',
textAlign: 'left',
flex: 1,
fontFamily: 'Prompt-Regular',
marginLeft: 0,
},
headerTitleContainerStyle: {
alignItems: 'center',
justifyContent: 'center',
},
headerLeftContainerStyle: {
alignItems: 'center',
justifyContent: 'center',
width: '10%',
},
headerTitleAllowFontScaling: false,
headerLeft: (
<TouchableOpacity
style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }}
onPress={() => navigation.goBack()}>
<Icon name="ic_back" size={20} color="#fff"/>
</TouchableOpacity>
),
headerRight: (
navigation.state.params.statusRepair !== 'Success' && navigation.state.params.statusRepair !== 'Cancel' && navigation.state.params.type !== 'effect_repair' &&
<TouchableOpacity onPress={() => navigation.state.params.cancelRepair()} style={{marginRight: 15}}>
<Text style={{color: '#FF3B30', fontSize: 18}}>{t('cancel')}</Text>
</TouchableOpacity>
)
})
},
//Reward //Reward
Reward: screenConfig(RewardScreen, 'redeem_reward'), Reward: screenConfig(RewardScreen, 'redeem_reward'),
RewardDetail: screenConfig(RewardDetailScreen,'product_detail'), RewardDetailScreen: screenConfig(RewardDetailScreen, 'product_detail'),
//Redeem
Redeem: screenConfig(RedeemScreen, 'reward'),
HistoryRedeem: screenConfig(HistoryRedeem, 'history_point'),
AllRewards: screenConfig(AllRewards, 'all_reward'),
MyRewards: screenConfig(MyRewards, 'my_reward'),
RewardDetail: screenConfig(RewardDetail, 'all_reward'),
ScanCoupon: {
screen: ScanCoupon,
navigationOptions: ({navigation}) => ({
title: t('coupon'),
...defaultHeaderStyle(),
headerLeft: () => {
console.log('navigation state', navigation.state)
return HeaderLeftComponent(navigation, 'MyRewards', {index: navigation.state.params.index})
}
})
},
RewardTermCondition: screenConfig(RewardTermCondition, 'term_condition'),
MembershipLevelDetail: screenConfig(MembershipLevelDetail, 'membership_detail'),
MemberPoinExpire: screenConfig(MemberPoinExpire, 'membership_detail'),
//Terms and Condition //Terms and Condition
Terms: screenConfig(TermsAndCondition, 'term_condition'), Terms: {
}) screen: TermsAndCondition,
navigationOptions: ({navigation}) => ({
title: t('term_condition'),
...defaultHeaderStyle(),
const styles = StyleSheet.create({ headerLeft: (
textBottomTab:{ <TouchableOpacity
fontSize:12, style={{ width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', }}
textAlign: 'center', onPress={() => {
store.dispatch(appCleanUser());
navigation.goBack()
}}>
<Icon name="ic_back" size={20} color="#fff"/>
</TouchableOpacity>
),
headerRight: (
<TouchableOpacity>
{/*<Icon name="ic_back" size={20} color="#fff"/>*/}
</TouchableOpacity>
)
})
} }
}) })
const styles = StyleSheet.create({
textBottomTab: {
fontSize: 12,
textAlign: 'center',
},
defaultHeaderStyle: {
backgroundColor: '#00420A',
height: 50,
marginTop: 25,
elevation: 0,
shadowOpacity: 0,
},
defaultHeaderTitleStyle: {
fontWeight: '400',
fontSize: 18,
color: '#fff',
textAlign: 'left',
flex: 1,
fontFamily: 'Prompt-Regular',
marginLeft: 0,
},
defaultHeaderTitleContainerStyle: {
alignItems: 'center',
justifyContent: 'center',
},
defaultHeaderLeftContainerStyle: {
alignItems: 'center',
justifyContent: 'center',
width: '10%',
},
})
export default AppStack export default AppStack

View File

@ -1,5 +1,5 @@
import { switchLanguage } from 'src/utils/i18n' import { switchLanguage } from 'src/utils/i18n'
import { setLanguage } from '../../api/api' import { setBaseUrlByServerMode, setLanguage } from '../../api/api'
// action type // action type
export const ACTION_APP_SET_TOKEN = 'APP_SET_TOKEN' 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_SET_PROJECT_ID = 'ACTION_APP_SET_PROJECT_ID'
export const ACTION_APP_CLEAN_PROJECT_ID = 'ACTION_APP_CLEAN_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_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 // action creator
export function appSetToken (token) { export function appSetToken (token) {
console.log('token appSetToken >>>>>>>>>>>>>>> ', token)
return { return {
type: ACTION_APP_SET_TOKEN, type: ACTION_APP_SET_TOKEN,
token token
@ -96,4 +99,19 @@ export function appSetLanguage (langCode) {
type: ACTION_APP_SET_LANGUAGE, type: ACTION_APP_SET_LANGUAGE,
lang: 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_SET_PROJECT_ID,
ACTION_APP_CLEAN_PROJECT_ID, ACTION_APP_CLEAN_PROJECT_ID,
ACTION_APP_SET_LANGUAGE, ACTION_APP_SET_LANGUAGE,
ACTION_APP_SET_SERVER_MODE,
ACTION_SET_POPUP_NOTIFICATION
} from './action' } from './action'
const initialState = { const initialState = {
@ -21,35 +23,40 @@ const initialState = {
notification: null, notification: null,
project_id: null, project_id: null,
lang: null, lang: null,
}; server_mode: 'production',
}
export default function (state = initialState, action) { export default function (state = initialState, action) {
switch (action.type) { switch (action.type) {
case ACTION_APP_SET_LANGUAGE: case ACTION_APP_SET_LANGUAGE:
return { ...state, lang: action.lang } return { ...state, lang: action.lang }
case ACTION_APP_SET_TOKEN: case ACTION_APP_SET_TOKEN:
return { ...state, token: action.token }; return { ...state, token: action.token }
case ACTION_APP_CLEAN_TOKEN: case ACTION_APP_CLEAN_TOKEN:
return { ...state, token: null }; return { ...state, token: null }
case ACTION_APP_SET_PUSH_TOKEN: case ACTION_APP_SET_PUSH_TOKEN:
return { ...state, push_token: action.pushToken }; return { ...state, push_token: action.pushToken }
case ACTION_APP_SET_DEVICE: case ACTION_APP_SET_DEVICE:
return { ...state, device: action.device }; return { ...state, device: action.device }
case ACTION_APP_CLEAN_DEVICE: case ACTION_APP_CLEAN_DEVICE:
return { ...state, device: null }; return { ...state, device: null }
case ACTION_APP_SET_USER: case ACTION_APP_SET_USER:
return { ...state, user: action.user }; return { ...state, user: action.user }
case ACTION_APP_CLEAN_USER: case ACTION_APP_CLEAN_USER:
return { ...state, user: null }; return { ...state, user: null }
case ACTION_APP_SET_NOTIFICATION: case ACTION_APP_SET_NOTIFICATION:
return { ...state, count_noti: action.count_noti }; return { ...state, count_noti: action.count_noti }
case ACTION_APP_CHANGE_NOTIFICATION: case ACTION_APP_CHANGE_NOTIFICATION:
return { ...state, notification: action.notification }; return { ...state, notification: action.notification }
case ACTION_APP_SET_PROJECT_ID: 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: 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: default:
return state return state
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react' 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 CameraRoll from "@react-native-community/cameraroll";
import {View} from "native-base"; import {View} from "native-base";
import Text from '../../components/Text'; import Text from '../../components/Text';
@ -8,6 +8,7 @@ import ViewShot, { captureRef } from "react-native-view-shot";
import IndicatorLoading from '../../components/IndicatorLoading'; import IndicatorLoading from '../../components/IndicatorLoading';
import QRCode from 'react-native-qrcode-svg'; import QRCode from 'react-native-qrcode-svg';
import { t } from '../../utils/i18n'; import { t } from '../../utils/i18n';
import Image from 'react-native-fast-image'
class PaymentScreen extends Component { class PaymentScreen extends Component {
constructor(props) { constructor(props) {
@ -26,11 +27,24 @@ class PaymentScreen extends Component {
this.setState({isLoading:true}) this.setState({isLoading:true})
payment_detail(this.state.payment_id) payment_detail(this.state.payment_id)
.then( res => { .then( res => {
this.setState({ if(res.data && res.data.success){
payment_data: res.data this.setState({
},() => { payment_data: res.data
this.setState({isLoading: false}) },() => {
}) this.setState({isLoading: false})
})
}else {
Alert.alert(res.data.message, '', [{
text: 'ok',
onPress: () => {
this.setState({
isLoading: false
}, () => {
this.props.navigation.goBack()
})
}
}])
}
}) })
}; };
@ -81,23 +95,24 @@ class PaymentScreen extends Component {
render(){ render(){
return( return(
<ImageBackground source={require('../../../assets/images/tree2.png')} style={{width: '100%', height: '100%', backgroundColor:'#EEFFD7'}}> <ImageBackground source={require('../../../assets/images/tree2.png')} style={{width: '100%', height: '100%', backgroundColor:'#EEFFD7'}}>
<ScrollView contentContainerStyle={styles.contentContainer}> <ViewShot style={{flex: 1}} options={{format: "jpg", quality: 1}} ref={ref => this.viewshot = ref}>
<View style={{flex: 1}}> <ScrollView contentContainerStyle={styles.contentContainer}>
<View style={{ alignItems: 'center', padding:20}}> <View style={styles.QrContainer}>
<ViewShot style={{width: '100%',alignItems:'center'}} options={{format: "jpg", quality: 1}} ref={ref => this.viewshot = ref}> <View style={styles.headerQr}>
<View style={{backgroundColor:'white', borderRadius:10,width: '90%',alignItems:'center'}}> <Image source={require('../../../assets/images/icon_payment.png')} style={{height: 40}} resizeMode={'contain'}/>
<View style={{width: '100%',backgroundColor:'#29558D',height: 55,borderTopLeftRadius:10,borderTopEndRadius:10,alignItems:'center',justifyContent:'center'}}> </View>
<Image source={require('../../../assets/images/icon_payment.png')} style={{height: 40}} resizeMode={'contain'}/> <Image source={require('../../../assets/images/icon_promptpay.png')} style={{height: 35, marginVertical: 18}} resizeMode={'contain'}/>
</View> <Text style={{fontSize: 18,color:'#00420A', textAlign: 'center'}}>{t('scan_to_pay')}</Text>
<Image source={require('../../../assets/images/icon_promptpay.png')} style={{height: 24,marginVertical: 18}} resizeMode={'contain'}/> <View style={{flex: 0.9, alignItems: 'center'}}>
<Text style={{fontSize: 18,color:'#00420A'}}>{t('scan_to_pay')}</Text> {/* <Image source={{uri: this.state.payment_data.qr}} style={{flex: 1}} resizeMode="contain"/> */}
<View style={{paddingVertical:10}}> <View style={{paddingVertical:10}}>
<QRCode <QRCode
value={this.state.payment_data.qr} value={this.state.payment_data.qr}
size={140} size={140}
color='black' color='black'
backgroundColor='white'/> backgroundColor='white'/>
</View> </View>
<View style={{alignItems: 'center'}}>
<Text style={{fontSize: 12,color:'#000000'}}>อบญช : {this.state.payment_data.receiver_name}</Text> <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: 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> <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'}}/> <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> <Text style={{fontSize: 10,color:'#00000080',marginBottom: 10}}>Accepts all banks | {t('support_all_bank')}</Text>
</View> </View>
</ViewShot> </View>
</View> </View>
<View style={{alignItems: 'center', paddingHorizontal:20}}> </ScrollView>
<TouchableOpacity style={{backgroundColor:'#269A21',width: '90%',height: 40,justifyContent:'center',alignItems:'center',borderRadius:5}} onPress={this.snapScreen}> </ViewShot>
<Text style={{color:'white',fontSize:14}}>{t('save')}</Text>
</TouchableOpacity> <View style={{flex: 0.1, justifyContent: 'center'}}>
</View> <TouchableOpacity style={{backgroundColor:'#269A21',height: 40,justifyContent:'center',alignItems:'center',borderRadius:5, marginHorizontal: 20}}
</View> onPress={this.snapScreen}>
</ScrollView> <Text style={{color:'white',fontSize:14}}>{t('save')}</Text>
</TouchableOpacity>
</View>
<IndicatorLoading loadingVisible={this.state.isLoading}/> <IndicatorLoading loadingVisible={this.state.isLoading}/>
</ImageBackground> </ImageBackground>
) )
@ -133,11 +150,24 @@ const styles = StyleSheet.create({
alignItems: 'center' alignItems: 'center'
}, },
contentContainer: { contentContainer: {
paddingVertical: 0, flex:1,
flex:1 padding: 20
}, },
colorTextPayment: { colorTextPayment: {
color: '#7CBB33' 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 { TouchableOpacity, View, Alert, ScrollView, SafeAreaView, KeyboardAvoidingView, Platform } from 'react-native'
import Image from 'react-native-fast-image' import Image from 'react-native-fast-image'
import GetWidthHeightDevice from '../../components/GetWidthHeightDevice' import GetWidthHeightDevice from '../../components/GetWidthHeightDevice'
import { CustomButton } from '../../components/CustomButton' import { CustomButton } from '../../components/CustomButton'
import { CustomInput } from '../../components/CustomInput' import { CustomInput } from '../../components/CustomInput'
import { login } from '../../api/UserApi' import {login, payment} from '../../api/UserApi'
import { setToken } from '../../api/api' import { setToken } from '../../api/api'
import { BackgroundImage } from '../../components/BackgroundImage' import { BackgroundImage } from '../../components/BackgroundImage'
import LinearGradient from 'react-native-linear-gradient' import LinearGradient from 'react-native-linear-gradient'
import Text from '../../components/Text' import Text from '../../components/Text'
import { bindActionCreators } from 'redux' 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 {connect} from 'react-redux'
import IndicatorLoading from '../../components/IndicatorLoading'; import IndicatorLoading from '../../components/IndicatorLoading';
import { locale, t } from '../../utils/i18n' import { locale, t } from '../../utils/i18n'
import moment from "moment";
import messaging from "@react-native-firebase/messaging";
class LoginScreen extends Component { class LoginScreen extends Component {
@ -22,50 +23,79 @@ class LoginScreen extends Component {
super(props) super(props)
this.state = { this.state = {
isLoading: false, isLoading: false,
username: null, username: '0935697758',
password: null, password: '123456',
payment: [],
sum_payment: [],
all_payment : [],
room_number_array : [],
} }
this._login = this._login.bind(this) this._login = this._login.bind(this)
} }
_login() { async _login () {
if (this.state.username && this.state.password) { if (this.state.username && this.state.password) {
var regex = /^\d+$/; var regex = /^\d+$/;
if (regex.test(this.state.username) === true) { if (regex.test(this.state.username) === true) {
let params = { console.log('true')
mobile: this.state.username,
password: this.state.password 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}) this.setState({isLoading:true})
login(params) login(params)
.then((res) => { .then((res) => {
if (res.ok) { if (res.ok) {
if (res.data.token) { console.log('data >>>>> ', res.data)
setToken(res.data.token) if (res.data.access_token) {
this.props.appSetToken(res.data.token) // setToken(res.data.token)
this.props.appSetUser(res.data.user) // 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})
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(() => { setTimeout(() => {
this.setState({isLoading:false},() => { Alert.alert(null, 'ท่านกรอก บัญชีผู้ใช้งาน หรือ รหัสผ่านผิด')
this.props.navigation.navigate('HomeScreen',{isLogin:true}) }, 600);
})
}, 300);
} }
} else { this.setState({isLoading:false})
setTimeout(() => { })
Alert.alert(null, 'ท่านกรอก บัญชีผู้ใช้งาน หรือ รหัสผ่านผิด')
}, 600);
}
this.setState({isLoading:false})
})
} else { } else {
Alert.alert(null, 'ท่านกรอกรูปแบบโทรศัพท์ไม่ถูกต้อง') Alert.alert(null, 'ท่านกรอกรูปแบบโทรศัพท์ไม่ถูกต้อง')
} }
} else { } else {
Alert.alert(null, 'กรุณากรอกข้อมูลให้ครบถ้วน') Alert.alert(null, 'กรุณากรอกข้อมูลให้ครบถ้วน')
} }
} };
render() { render() {
return ( return (
@ -137,6 +167,11 @@ class LoginScreen extends Component {
}} }}
style={styles.form_input} /> style={styles.form_input} />
</View> </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 }]}> <View style={[styles.row, { marginTop: 15 }]}>
<CustomButton <CustomButton
colorText={'#2470A1'} colorText={'#2470A1'}
@ -149,14 +184,14 @@ class LoginScreen extends Component {
//onPress={() => { this.props.navigation.navigate('HomeScreen') }} //onPress={() => { this.props.navigation.navigate('HomeScreen') }}
/> />
</View> </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' }]}> <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') }}> <TouchableOpacity onPress={() => { this.props.navigation.navigate('Register') }}>
<Text style={{ color: '#FFF', fontSize: 15, fontFamily: 'Prompt-Bold' }}> {t('create_account')} </Text> <Text style={{ color: '#FFF', fontSize: 15, fontFamily: 'Prompt-Bold' }}> {t('create_account')} </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View> */}
</View> </View>
</View> </View>
</ScrollView> </ScrollView>

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -4,14 +4,25 @@ import Text from '../../components/Text';
import { Badge } from 'native-base' import { Badge } from 'native-base'
import { WebView } from 'react-native-webview'; import { WebView } from 'react-native-webview';
import { t } from '../../utils/i18n' 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) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
currentLocale: 'th'
}; };
} }
componentDidMount(): void {
this.setState({
currentLocale : I18n.currentLocale()
})
}
render() { render() {
return ( return (
<ScrollView contentContainerStyle={{flex:1}}> <ScrollView contentContainerStyle={{flex:1}}>
@ -26,7 +37,8 @@ export default class TermsAndCondition extends Component {
flex: 1, flex: 1,
}} }}
originWhitelist={['*']} 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} javaScriptEnabled={true}
domStorageEnabled={true} domStorageEnabled={true}
onNavigationStateChange={(event) => { onNavigationStateChange={(event) => {
@ -41,6 +53,7 @@ export default class TermsAndCondition extends Component {
</View> </View>
<View style={{flexDirection:'row',justifyContent:'space-around',height:60}}> <View style={{flexDirection:'row',justifyContent:'space-around',height:60}}>
<TouchableOpacity onPress={() => { <TouchableOpacity onPress={() => {
this.props. appCleanUser();
this.props.navigation.goBack() this.props.navigation.goBack()
}}> }}>
<View> <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) 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(){ getMeter(){
this.setState({ this.setState({
isLoading: true isLoading: true
@ -71,7 +77,8 @@ export default class Meter extends Component {
cropping: true, cropping: true,
width: 300, width: 300,
height: 100, height: 100,
includeExif: true includeExif: true,
includeBase64: true
}).then(image => { }).then(image => {
console.log('received image', image) console.log('received image', image)
let image_meter = { let image_meter = {
@ -79,13 +86,15 @@ export default class Meter extends Component {
type: image.mime, type: image.mime,
name: 'image_meter.jpg', name: 'image_meter.jpg',
} }
let image_data = { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height};
this.setState({ this.setState({
image_url: {uri: image.path, width: image.width, height: image.height, mime: image.mime}, image_url: image_data,
images: null, images: null,
image_preview: image_meter
}, () => { }, () => {
this.selectedImage(this.state.image_url) this.selectedImage(this.state.image_url)
}) })
}).catch(e => alert(e)) }).catch(e => {})
} }
selectedImage(image_meter){ selectedImage(image_meter){
@ -94,9 +103,9 @@ export default class Meter extends Component {
},() => { },() => {
console.log('selected image ',this.state.image_selected) console.log('selected image ',this.state.image_selected)
if(this.state.selected_type == 'pea'){ 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{ }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; _keyExtractor = (item, index) => 'meter_room_'+index;
_renderItem = ({item}) => ( _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 }}> <View style={{ justifyContent: 'center',padding:16 }}>
<Text style={{ color: 'white', fontSize: 16 }}>{item.name}</Text> <Text style={{ color: 'white', fontSize: 16 }}>{item.name}</Text>
<Text style={{ color: 'white', fontSize: 16 }}>{item.project_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={{paddingHorizontal:16,height: 96,backgroundColor:'white',borderWidth:1,borderColor:'#EAEAF4'}}>
<View style={{flex:1,flexDirection:'row'}}> <View style={{flex:1,flexDirection:'row'}}>
<View style={{height: 96,justifyContent:'center',marginRight:16}}> <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>
<View style={{flex:1,justifyContent:'center'}}> <View style={{flex:1,justifyContent:'center'}}>
<View style={styles.viewTextFlatlist}> <View style={styles.viewTextFlatlist}>

View File

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

View File

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

View File

@ -20,7 +20,7 @@ export default class SaveViewMeter extends Component {
<View style={{justifyContent:'center',alignItems:'center'}}> <View style={{justifyContent:'center',alignItems:'center'}}>
<Image source={{uri:this.props.ImageUri}} resizeMode={'contain'} style={{borderRadius:5,height: 184,width:'100%'}}/> <Image source={{uri:this.props.ImageUri}} resizeMode={'contain'} style={{borderRadius:5,height: 184,width:'100%'}}/>
</View> </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'}} <TouchableOpacity style={{height: 40,width: '100%',backgroundColor:'#007AFF',justifyContent:'center',alignItems:'center',borderRadius:5,flexDirection:'row'}}
onPress={this.props.onTakeCamera}> onPress={this.props.onTakeCamera}>
<Icon nane={'ic_outline_camera'} size={22} color={'#FFFFFF'}/> <Icon nane={'ic_outline_camera'} size={22} color={'#FFFFFF'}/>

View File

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

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react' import React, { Component, Fragment } from 'react'
import { 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' } from 'react-native'
import Image from 'react-native-fast-image' import Image from 'react-native-fast-image'
import ImageBackground 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 { BackgroundImage } from '../../components/BackgroundImage'
import Text from '../../components/Text' import Text from '../../components/Text'
import { NavigationEvents } from 'react-navigation' 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 { bindActionCreators } from 'redux'
import { import {
appSetDevice, appSetDevice,
@ -27,13 +27,111 @@ import { connect } from 'react-redux'
import moment from 'moment' import moment from 'moment'
import IndicatorLoading from '../../components/IndicatorLoading' import IndicatorLoading from '../../components/IndicatorLoading'
import { loginWithFacebook } from '../../components/FacebookUtils' import { loginWithFacebook } from '../../components/FacebookUtils'
import { signinApple } from '../../components/AppleAuth'
import parseDateLocale from '../../utils/parseDateLocale'
import { from } from 'rxjs' import { from } from 'rxjs'
//import Slideshow from 'react-native-image-slider-show'; //import Slideshow from 'react-native-image-slider-show';
import appleAuth, {
AppleButton,
} from '@invertase/react-native-apple-authentication';
import { t, locale } from '../../utils/i18n' import { t, locale } from '../../utils/i18n'
import messaging from "@react-native-firebase/messaging";
import {store} from '../../redux/store';
const { height, width } = Dimensions.get('window') const { height, width } = Dimensions.get('window')
console.disableYellowBox = true 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 { class NewsScreen extends Component {
constructor (props) { constructor (props) {
super(props) super(props)
@ -59,7 +157,7 @@ class NewsScreen extends Component {
is_new: false is_new: false
}], }],
due_at: '', due_at: '',
pending_payment: '', pending_payment: 0,
noti_count: 0, noti_count: 0,
isFirstTime: true, isFirstTime: true,
user_point: 0, user_point: 0,
@ -70,9 +168,20 @@ class NewsScreen extends Component {
scrollY: new Animated.Value(0), scrollY: new Animated.Value(0),
loadMore: false, loadMore: false,
loadPage: 1, loadPage: 1,
last_page: 1,
isLoadmore: false, isLoadmore: false,
fb_is_link: false, fb_is_link: false,
email: '', 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) this._onCarouselScroll = this._onCarouselScroll.bind(this)
@ -80,18 +189,51 @@ class NewsScreen extends Component {
} }
componentDidMount () { 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 () { async getUser () {
if (this.props.token != null) { if (this.props.token != null) {
return await getUserProfile() return await getUserProfile()
.then(res => { .then(async res => {
if (res.ok) { if (res.ok) {
console.log("News:: res.data:") console.log("News:: res.data:")
console.log(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({ this.setState({
pending_payment: res.data.pending_payment != null ? res.data.pending_payment : 0,
noti_count: res.data.count_noti, noti_count: res.data.count_noti,
user_point: res.data.point_balance, user_point: res.data.point_balance,
user_project_id: res.data.project_id, user_project_id: res.data.project_id,
@ -106,101 +248,160 @@ class NewsScreen extends Component {
} }
}) })
} else { } else {
setTimeout(() => { //setTimeout(() => {
this.setState({ this.setState({
isLoading: false isLoading: false
}, () => { }, () => {
this.props.appCleanUser() this.props.appCleanUser()
this.props.appCleanToken() this.props.appCleanToken()
}) })
}, 600) //}, 600)
} }
}) })
}else {
await this.getAllNewsList()
} }
return true return true
} }
async getAllNewsByProject(project_id) {
return getNewsByProject(project_id)
.then(res => {
console.log('res >>>>>>> ', res)
this.setNewsData(res)
})
}
async getAllNewsList () { async getAllNewsList () {
// return getNews() // return getNews()
return getNewsPage(this.state.loadPage) return getNewsPage(this.state.loadPage)
.then(res => { .then(res => {
if ((res.data.data).length > 5) { this.setNewsData(res)
var cut = []
for (let index = 0; index < 5; index++) {
cut.push(res.data.data[index])
}
this.setState({
user: this.props.user,
news_head: cut,
new_all: res.data.data,
refreshing: false,
isLoading: false
})
} else {
this.setState({
news_head: res.data.data,
new_all: res.data.data,
refreshing: false,
isLoading: false
})
}
}) })
} }
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])
}
this.setState({
user: this.props.user,
news_head: cut,
new_all: res.data.data,
refreshing: 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,
last_page: res.data.last_page
})
}
}
initData () { initData () {
this.setState({ isLoading: true }) console.log('initData >>> ')
Promise.all([ this.setState({
this.getUser(), isLoading: true,
this.getAllNewsList() loadPage: 1,
]) last_page: 1,
.then(() => { news_head: [{
let user_id = 0 title: 'กำลังโหลดข้อมูลข่าว',
let user_noti_id = 0 content: 'กำลังโหลดข้อมูลข่าว',
if (this.props.token != null) { date: 'กำลังโหลดข้อมูลข่าว',
if (this.state.isFirstTime) { is_new: false
this.props.appSetNotification(this.state.noti_count) }],
this.props.appSetProjectID(this.state.user_project_id) new_all: [{
this.setState({ isFirstTime: false }) title: 'กำลังโหลดข้อมูลข่าว',
content: 'กำลังโหลดข้อมูลข่าว',
date: 'กำลังโหลดข้อมูลข่าว',
is_new: false
}],
}, () => {
Promise.all([
this.getUser(),
// this.getAllNewsList()
])
.then(() => {
let user_id = 0
let user_noti_id = 0
if (this.props.token != null) {
if (this.state.isFirstTime) {
this.props.appSetNotification(this.state.noti_count)
this.props.appSetProjectID(this.state.user_project_id)
this.setState({ isFirstTime: false })
}
} }
}
if (this.props.user && this.props.user.id) { if (this.props.user && this.props.user.id) {
user_id = this.props.user.id user_id = this.props.user.id
user_noti_id = this.props.user.id user_noti_id = this.props.user.id
} else if (this.props.device && this.props.device.customer_id) { } else if (this.props.device && this.props.device.customer_id) {
user_noti_id = this.props.device.customer_id user_noti_id = this.props.device.customer_id
} }
if (this.props.token != null && this.props.user != null) { if (this.props.token != null && this.props.user != null) {
this.setState({ this.setState({
auth: true, auth: true,
}) })
} else { } else {
this.setState({ this.setState({
auth: false auth: false
}) })
} }
this.setState({ isLoading: false }) this.setState({ isLoading: false })
}) })
.catch(() => { .catch(() => {
// console.log('catch ------------------>'); // console.log('catch ------------------>');
// this.setState({isLoading:false}) // this.setState({isLoading:false})
// this.props.appCleanUser() // this.props.appCleanUser()
// this.props.appCleanToken() // this.props.appCleanToken()
setTimeout(() => {
this.setState({
isLoading: false
}, () => {
//this.props.appCleanUser()
//this.props.appCleanToken()
})
}, 600)
// 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))
}
}
setTimeout(() => {
this.setState({
isLoading: false
}, () => {
this.props.appCleanUser()
this.props.appCleanToken()
})
}, 600)
this.initData()
})
} }
_onRefresh = () => { _onRefresh = () => {
@ -208,21 +409,59 @@ class NewsScreen extends Component {
refreshing: true, loadPage: 1, loadMore: false refreshing: true, loadPage: 1, loadMore: false
}, () => { }, () => {
this.initData() 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 }) => ( renderNativeItem = ({ item }) => (
<TouchableOpacity style={{ padding: 8, backgroundColor: '#FFFFFF33', height: 85, borderWidth: 1, borderColor: 'white', borderRadius: 5, flexDirection: 'row' }} <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 })}}> 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' }}> <View style={{ flex: 1, marginLeft: 8, justifyContent: 'space-between' }}>
<Text style={{ fontSize: 14, color: 'white', width: '100%', }} ellipsizeMode={'tail'} numberOfLines={2}>{item.title}</Text> <Text style={{ fontSize: 14, color: 'white', width: '100%', }} ellipsizeMode={'tail'} numberOfLines={2}>{item.title}</Text>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Icon name="ic_calendar_alt" size={16} color="white"/> <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' }}> <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> <Text style={{ fontSize: 12, color: 'white' }}>{item.type == "promotion" ? t('latest_promotion') : t('latest_news')}</Text>
</View> </View>
}
</View> </View>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
@ -232,17 +471,21 @@ class NewsScreen extends Component {
return <TouchableOpacity onPress={() => { return <TouchableOpacity onPress={() => {
this.props.navigation.navigate('NewsDetail', { news_id: item.id }) 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']}> <LinearGradient colors={['rgba(0, 0, 0, 0)', '#000000']}>
<View style={{ padding: 15, }}> <View style={{ padding: 15, }}>
{item.is_new == true ? {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 } : null }
<Text style={styles.textNewsName} ellipsizeMode={'tail'} numberOfLines={2}>{item.title}</Text> <Text style={styles.textNewsName} ellipsizeMode={'tail'} numberOfLines={2}>{item.title}</Text>
<View style={{ flexDirection: 'row', marginTop: 5 }}> <View style={{ flexDirection: 'row', marginTop: 5 }}>
<Icon name="ic_calendar_alt" size={14} color="rgba(255, 255, 255, 0.65)"/> <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 }}> <Text style={{ color: 'rgba(255, 255, 255, 0.65)', fontSize: 12, marginLeft: 5, marginTop: -1 }}>
{item.date} {parseDateLocale(item.date)}
</Text> </Text>
</View> </View>
</View> </View>
@ -251,21 +494,11 @@ class NewsScreen extends Component {
</TouchableOpacity> </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) { _onCarouselScroll (e) {
const scrollX = e.nativeEvent.contentOffset.x const scrollX = e.nativeEvent.contentOffset.x
this.setState({ this.setState({
position: Math.ceil(scrollX / width) position: Math.ceil(scrollX / width)
}) })
// console.log(this.state.position) // console.log(this.state.position)
} }
@ -276,41 +509,32 @@ class NewsScreen extends Component {
} }
loadMoreData = async () => { loadMoreData = async () => {
const { loadMore } = this.state if(parseInt(this.state.loadPage) < parseInt(this.state.last_page)){
if (loadMore) { this.setState({
return loadMore: true,
} isLoadmore: true,
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_all = this.state.new_all
let news_arr = news_all.concat(resData)
let loadpage = this.state.loadPage + 1 this.setState({
new_all: news_arr,
refreshing: false,
loadMore: false,
isLoadmore: false,
last_page: res.data.last_page
})
}
})
})
}
/*loading - set loadMore = false when done*/ /*loading - set loadMore = false when done*/
getNewsPage(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)
})
this.setState({
loadPage: loadpage,
new_all: news_arr,
refreshing: false,
loadMore: false,
isLoadmore: false
})
if (resData.length < 10) {
this.setState({
loadMore: true
})
return
}
}
})
} }
_keyExtractorNewHead = (item, index) => 'new_head_' + index _keyExtractorNewHead = (item, index) => 'new_head_' + index
@ -326,14 +550,19 @@ class NewsScreen extends Component {
}}> }}>
<NavigationEvents <NavigationEvents
onDidFocus={() => { onDidFocus={() => {
this.setState({ isLoading: true }) this.setState({
let checkNav = this.props.navigation.getParam('isLogin') isLoading: true
}, () => {
this.initData()
// this.checkNotifiedPopup()
})
/*let checkNav = this.props.navigation.getParam('isLogin')
if (checkNav) { if (checkNav) {
this.props.navigation.setParams({ isLogin: false }) this.props.navigation.setParams({ isLogin: false })
this.initData() this.initData()
} else { } else {
this.setState({ isLoading: false }) this.setState({ isLoading: false })
} }*/
}} }}
/> />
<BackgroundImage> <BackgroundImage>
@ -347,7 +576,8 @@ class NewsScreen extends Component {
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
scrollEventThrottle={16} scrollEventThrottle={16}
onScroll={Animated.event( onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }] [{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
{useNativeDriver: false}
)} )}
onMomentumScrollEnd={({ nativeEvent }) => { onMomentumScrollEnd={({ nativeEvent }) => {
if (this.isCloseToBottom(nativeEvent)) { if (this.isCloseToBottom(nativeEvent)) {
@ -366,7 +596,11 @@ class NewsScreen extends Component {
onScroll={this._onCarouselScroll} onScroll={this._onCarouselScroll}
/> />
<View style={{ position: 'absolute', bottom: 10, width: '100%', justifyContent: 'center', flexDirection: 'row' }}> <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>
</View> </View>
{this.state.auth !== null && {this.state.auth !== null &&
@ -377,9 +611,9 @@ class NewsScreen extends Component {
<View style={{ flex: 1, alignItems: 'center', padding: 10 }}> <View style={{ flex: 1, alignItems: 'center', padding: 10 }}>
<View> <View>
<Text style={{ color: 'white', fontSize: 16, textAlign: 'center' }}>{t('for_csa_customer')}</Text> <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> </View>
<TouchableOpacity onPress={() => { {/*<TouchableOpacity onPress={() => {
// this.props.navigation.navigate('Register') // this.props.navigation.navigate('Register')
this.props.navigation.navigate('Terms') 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> <Text style={{ fontSize: 16, color: 'white', padding: 5, textAlign: 'center' }}>{t('create_account')}</Text>
</Badge> </Badge>
</View> </View>
</TouchableOpacity> </TouchableOpacity>*/}
<Text style={{ color: 'white', marginTop: 10 }}>{t('or')}</Text> {/* <Text style={{ color: 'white', marginTop: 10 }}>{t('or')}</Text> */}
<TouchableOpacity onPress={() => { this.props.navigation.navigate('Login') }}> <TouchableOpacity onPress={() => { this.props.navigation.navigate('Login') }}>
<View> <View>
<Badge style={{ backgroundColor: '#145EB3', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', marginTop: 10, height: null, width: 150 }}> <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> </Badge>
</View> </View>
</TouchableOpacity> </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> <Text style={{ color: 'white', marginTop: 10 }}>{t('or')}</Text>
<TouchableOpacity onPress={() => { <TouchableOpacity onPress={() => {
loginWithFacebook(() => { loginWithFacebook(() => {
this.initData() this.initData()
}) })
@ -408,7 +658,7 @@ class NewsScreen extends Component {
loginWithFacebook(() => { loginWithFacebook(() => {
this.initData() this.initData()
}) })
}else{ }else
Alert.alert( Alert.alert(
"", "",
"อิเมล์ "+this.state.email+" ยังไม่ได้ลงทะเบียนในระบบ กรุณาสมัครสมาชิก", "อิเมล์ "+this.state.email+" ยังไม่ได้ลงทะเบียนในระบบ กรุณาสมัครสมาชิก",
@ -435,7 +685,7 @@ class NewsScreen extends Component {
<View style={{ padding: 5 }}> <View style={{ padding: 5 }}>
<View style={[styles.row, { alignItems: 'stretch' }]}> <View style={[styles.row, { alignItems: 'stretch' }]}>
<View style={styles.custom_card}> <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> <BackgroundImage_RegisterForm>
<View style={{ flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 10, minHeight: 177 }}> <View style={{ flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 10, minHeight: 177 }}>
<View style={{ justifyContent: 'center', alignItems: 'center' }}> <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: 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 }}>{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> <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> </View>
<TouchableOpacity disabled={!this.state.isBilling} onPress={() => {this.props.navigation.navigate('Bill')}}> <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>*/} {/*<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> </BackgroundImage_RegisterForm>
</Card> </Card>
</View> </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 }}> <Card title='' style={{ borderRadius: 5, backgroundColor: '#003114', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
<BackgroundImage_RegisterForm> <BackgroundImage_RegisterForm>
<View style={{ <View style={{
@ -471,12 +721,14 @@ class NewsScreen extends Component {
<Icon name='ic_star' color='white' size={24}/> <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 }}>คะแนนสะสม</Text>*/}
<Text style={{ color: 'white', fontSize: 14, marginTop: 5 }}>{t('view_points')}</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: 18 }}>พอยต์</Text>*/}
<Text style={{ color: 'white', fontSize: 14 }}>{t('point')}</Text> <Text style={{ color: 'white', fontSize: 14 }}>{t('point')}</Text>
<TouchableOpacity style={{ marginTop: 5 }} disabled={true} onPress={() => {}}> <TouchableOpacity style={{ marginTop: 5 }}
{/*<Badge style={{ backgroundColor: 'gray', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', justifyContent:'center' }}><Text style={{ fontSize: 12, color: 'white' }}>แลกคะแนน</Text></Badge>*/} onPress={() => {this.props.navigation.navigate('Redeem')}}>
<Badge style={{ backgroundColor: 'gray', borderRadius: 5, borderColor: 'rbga(0,0,0,0)', justifyContent: 'center' }}><Text style={{ fontSize: 12, color: 'white' }}>{t('redeem')}</Text></Badge> <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> </TouchableOpacity>
</View> </View>
</BackgroundImage_RegisterForm> </BackgroundImage_RegisterForm>
@ -484,55 +736,54 @@ class NewsScreen extends Component {
</View> </View>
</View> </View>
<View style={[styles.row, { flexWrap: 'wrap', alignItems: 'stretch' }]}> <View style={[styles.row, { flexWrap: 'wrap', alignItems: 'stretch' }]}>
{this.state.isMeter ? <View style={[styles.custom_card]}>
<View style={[styles.custom_card]}> <TouchableOpacity disabled={false} onPress={() => {
<TouchableOpacity disabled={false} onPress={() => { this.props.navigation.navigate('Meter')
this.props.navigation.navigate('Meter') }} style={{ flex: 1 }}>
}} style={{ flex: 1 }}> <Card title='' style={{ borderRadius: 5, backgroundColor: '#145EB3', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
<Card title='' style={{ borderRadius: 5, backgroundColor: '#145EB3', borderColor: 'rbga(0,0,0,0)', flex: 1 }}> <View style={{
<View style={{ flex: 1,
flex: 1, flexDirection: 'column',
flexDirection: 'column', alignItems: 'center',
alignItems: 'center', padding: 10,
padding: 10, justifyContent: 'center'
justifyContent: 'center' }}>
}}> <View style={{ alignItems: 'center' }}>
<View style={{ alignItems: 'center' }}> <Icon name='ic_meter' color='white' size={24}/>
<Icon name='ic_meter' color='white' size={24}/> <Text style={{ color: 'white', fontSize: 14, textAlign: 'center', marginTop: 5 }}> {t('smart_meter')} </Text>
<Text style={{ color: 'white', fontSize: 14, textAlign: 'center', marginTop: 5 }}> {t('smart_meter')} </Text>
</View>
</View> </View>
</Card> </View>
</TouchableOpacity> </Card>
</View> </TouchableOpacity>
: null} </View>
{this.state.isShipping ? <View style={[styles.custom_card]}>
<View style={[styles.custom_card]}> <TouchableOpacity disabled={false} onPress={() => {
<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 }}> }} style={{ flex: 1 }}>
<View style={{ <Card title='' style={{ borderRadius: 5, backgroundColor: '#145EB3', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
flex: 1, <View style={{
flexDirection: 'column', flex: 1,
alignItems: 'center', flexDirection: 'column',
padding: 10, alignItems: 'center',
justifyContent: 'center' padding: 10,
}}> justifyContent: 'center'
<View style={{ alignItems: 'center' }}> }}>
<Icon name='ic_cart' color='white' size={24}/> <View style={{ alignItems: 'center' }}>
<Text style={{ color: 'white', fontSize: 14, textAlign: 'center', marginTop: 5 }}>{t('mail_and_parcel')}</Text> <Icon name='ic_cart' color='white' size={24}/>
</View> <Text style={{ color: 'white', fontSize: 14, textAlign: 'center', marginTop: 5 }}>{t('mail_and_parcel')}</Text>
</View> </View>
</Card> </View>
</TouchableOpacity> </Card>
</View> </TouchableOpacity>
: null} </View>
<View style={[styles.custom_card]}> <View style={[styles.custom_card]}>
<TouchableOpacity disabled={false} <TouchableOpacity disabled={false}
onPress={() => { this.props.navigation.navigate('RepairService',{ /*onPress={() => { this.props.navigation.navigate('RepairService',{
user:this.props.user user:this.props.user
}) }} }) }}*/
onPress={() => { this.props.navigation.navigate('Repair')}}
style={{ flex: 1 }}> style={{ flex: 1 }}>
<Card title='' style={{ borderRadius: 5, backgroundColor: '#145EB3', borderColor: 'rbga(0,0,0,0)', flex: 1 }}> <Card title='' style={{ borderRadius: 5, backgroundColor: '#145EB3', borderColor: 'rbga(0,0,0,0)', flex: 1 }}>
<View style={{ <View style={{
@ -583,21 +834,59 @@ class NewsScreen extends Component {
data={this.state.new_all} data={this.state.new_all}
renderItem={this.renderNativeItem} renderItem={this.renderNativeItem}
keyExtractor={this._keyExtractorNewAll} keyExtractor={this._keyExtractorNewAll}
// onEndReachedThreshold={0.01}
// onEndReached={this.loadMoreData.bind(this)}
ItemSeparatorComponent={() => { ItemSeparatorComponent={() => {
return <View style={{ width: '100%', height: 8 }}></View> return <View style={{ width: '100%', height: 8 }}></View>
}} }}
ListFooterComponent={() => { ListFooterComponent={() => {
if (!this.state.isLoadmore) return null if (!this.state.isLoadmore) return null
return (<View style={{ padding: 16, flexDirection: 'row', borderRadius: 10, justifyContent: 'center', alignItems: 'center' }}> return (<ActivityIndicator
<ActivityIndicator size="small" color="black"/> size="large"
<Text style={{ fontSize: 12, marginLeft: 10, color: 'black' }}>Loading...</Text> color={'white'}
</View>) />)
}} }}
/> />
</View> </View>
</ScrollView> </ScrollView>
</BackgroundImage> </BackgroundImage>
<IndicatorLoading loadingVisible={this.state.isLoading}/> <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> </LinearGradient>
) )
} }
@ -649,6 +938,51 @@ const styles = StyleSheet.create({
custom_card: { custom_card: {
width: '50%', paddingHorizontal: 5, width: '50%', paddingHorizontal: 5,
// width: '100%' // 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 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) export default connect(mapDisPatchToProps, setUser)(NewsScreen)

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react' 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 Image from 'react-native-fast-image'
import { WebView } from 'react-native-webview'; import { WebView } from 'react-native-webview';
import { Body, Badge, List, ListItem, Right, Title } from 'native-base' 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 { getNewsDetail } from '../../api/UserApi';
import IndicatorLoading from '../../components/IndicatorLoading'; import IndicatorLoading from '../../components/IndicatorLoading';
import { t } from '../../utils/i18n' import { t } from '../../utils/i18n'
import parseDateLocale from '../../utils/parseDateLocale';
import ImageView from 'react-native-image-view'; import ImageView from 'react-native-image-view';
import {NavigationActions} from "react-navigation"; 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; var uri = null;
const injectScript = ` const injectScript = `
(function () { (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){ 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() this.props.navigation.state.params.getNotification()
} }
} }*/
getNewsData(){ getNewsData(){
this.setState({ this.setState({
@ -54,26 +57,34 @@ export default class NewsDetailScreen extends Component {
getNewsDetail(this.state.news_id) getNewsDetail(this.state.news_id)
.then(res => { .then(res => {
if(res.ok){ if(res.ok){
this.setState({ if(res.data.data){
isLoading: false, this.setState({
news_detail: res.data.data isLoading: false,
}) news_detail: res.data.data
}else{ })
this.setState({ }else {
isLoading: false, console.log('ถูกยกเลิกเผยแพร่ข่าว')
news_detail: [ Alert.alert('','ถูกยกเลิกเผยแพร่ข่าว', [{
{ text: t('ok'),
title: '', onPress: () => {
content: '', console.log('press')
style: '', this.setState({
is_new: true, isLoading: false,
date:'', news_detail: {}
url:'', })
} }
], }])
}
}) }else{
Alert.alert('','ถูกยกเลิกเผยแพร่ข่าว') Alert.alert('','ถูกยกเลิกเผยแพร่ข่าว', [{
text: t('ok'),
onPress: () => {
this.setState({
isLoading: false,
news_detail: {}
})
}
}])
// alert('ถูกยกเลิกเผยแพร่ข่าว') // alert('ถูกยกเลิกเผยแพร่ข่าว')
// this.context.router.goBack() // this.context.router.goBack()
@ -82,6 +93,25 @@ export default class NewsDetailScreen extends Component {
} }
render() { 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 ( return (
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{ <LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
flex: 1, flex: 1,
@ -89,29 +119,36 @@ export default class NewsDetailScreen extends Component {
height: null height: null
}}> }}>
<BackgroundImage> <BackgroundImage>
<ImageView {
images={[{source: {uri: this.state.news_detail != null && this.state.news_detail.url }}]} Platform.OS === 'android' &&
imageIndex={0} <ImageView
isVisible={this.state.isImageViewVisible} images={[{source: {uri: this.state.news_detail != null && this.state.news_detail.url ? this.state.news_detail.url : '' }}]}
animationType={'fade'} imageIndex={0}
/> isVisible={this.state.isImageViewVisible}
animationType={'fade'}
onClose={() => {this.setState({isImageViewVisible: false})}}
/>
}
<View> <View>
<TouchableOpacity onPress={() => {this.setState({isImageViewVisible: true})}}> <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> </TouchableOpacity>
</View> </View>
<View style={{ backgroundColor: 'white', padding: 15 }}> <View style={{ backgroundColor: 'white', padding: 15 }}>
<View style={{ flexDirection: 'row' }}> <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>
<View style={{ flexDirection: 'row', marginTop: 5 }}> <View style={{ flexDirection: 'row', marginTop: 5 }}>
<View style={{ width: '50%', flexDirection: "row", marginTop: 5 }}> <View style={{ width: '50%', flexDirection: "row", marginTop: 5 }}>
<Icon name="ic_event_note" size={16} color="#00420A" /> <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>
<View style={{ width: '50%', flexDirection: "row", flex: 1, justifyContent: 'flex-end' }}> <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 }}> {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' }}>{t('latest_news')} </Text> <Text style={{ fontSize: 12, color: 'white' }}>{this.state.news_detail.type === 'promotion' ? t('latest_promotion') : t('latest_news')} </Text>
</Badge> : null} </Badge> : null}
</View> </View>
</View> </View>
@ -127,26 +164,55 @@ export default class NewsDetailScreen extends Component {
flex: 1, flex: 1,
}} }}
originWhitelist={['*']} 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; }} ref={(ref) => { this.webview = ref; }}
javaScriptEnabled={true} javaScriptEnabled={true}
domStorageEnabled={true} domStorageEnabled={true}
// onShouldStartLoadWithRequest={(navState)=>{ //open external browser for android onMessage={(event) => {
// console.log('onShouldStartLoadWithRequest >>>>>> ',navState); if(event.nativeEvent.data){
// Linking.openURL(navState.url) let data = JSON.parse(event.nativeEvent.data);
// return false; if(data.video_id){
// }} Linking.openURL(`https://youtube.com/embed/${data.video_id}`);
}
}
}}
onNavigationStateChange={(event) => { /*onNavigationStateChange={(event) => {
console.log('onNavigationStateChange >>>>>> ',event); console.log('onNavigationStateChange >>>>>> ',event);
if (event.url.startsWith("http")) { if (event.url.startsWith("http")) {
this.webview.stopLoading(); this.webview.stopLoading();
this.webview.goBack(); this.webview.goBack();
Linking.openURL(event.url); Linking.openURL(event.url);
} }
}} }}*/
/> />
</BackgroundImage> </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}/> <IndicatorLoading loadingVisible={this.state.isLoading}/>
</LinearGradient> </LinearGradient>
) )
@ -167,5 +233,11 @@ const styles = StyleSheet.create({
textAlign: 'center', textAlign: 'center',
fontSize: 12 fontSize: 12
},
backgroundImage: {
flex: 1,
width: null,
height: null,
resizeMode: 'cover'
} }
}) })

View File

@ -1,5 +1,5 @@
import React, {Component} from 'react' 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 Image from 'react-native-fast-image'
import {BackgroundImage} from '../../components/BackgroundImage' import {BackgroundImage} from '../../components/BackgroundImage'
import LinearGradient from 'react-native-linear-gradient'; 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 {bindActionCreators} from 'redux'
import {appSetNotification} from '../../redux/app/action' import {appSetNotification} from '../../redux/app/action'
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import moment from "moment";
import { t } from '../../utils/i18n'; import { t } from '../../utils/i18n';
import parseDateLocale from '../../utils/parseDateLocale';
import { NavigationEvents } from "react-navigation";
const injectScript = ` const injectScript = `
(function () { (function () {
@ -33,9 +34,137 @@ class NotificationScreen extends Component {
} }
_set_read(item) { _set_read(item) {
read_notification(item.id).then(res => { switch (item.source_type) {
console.log('read noti => ', res.data.message) case 'payment_success':
}) case 'update_app':
return false;
default:
read_notification(item.id).then(res => {
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() { componentDidMount() {
@ -67,13 +196,13 @@ class NotificationScreen extends Component {
// console.log('user_noti_id => ', user_noti_id) // console.log('user_noti_id => ', user_noti_id)
if(this.props.token != null){ 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) { if (res.data) {
this.setState({ this.setState({
new_noti: res.data.data, new_noti: res.data.data,
page: res.data.current_page, page: res.data.current_page,
refreshing: false, refreshing: false,
last_page: res.data.last_page last_page: res.data.last_page
}); });
} }
}) })
@ -130,76 +259,79 @@ class NotificationScreen extends Component {
}); });
} }
getTypeNoti(source_type) { getTypeNoti(item) {
let type = 'ข่าวใหม่'; let type = 'ข่าวใหม่';
switch (source_type) { switch (item.source_type) {
case 'news': case 'news':
case 'general':
type = t('latest_news'); type = t('latest_news');
break; break;
case 'rooms': case 'rooms':
type = t('new_room'); type = t('new_room');
break; break;
case 'parcels':
type = t('new_parcel');
break;
case 'promotion': case 'promotion':
type = t('latest_promotion'); type = t('latest_promotion');
break; 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: default:
type = t('latest_news'); type = '';
break; break;
} }
return type; return type;
} }
getDateNoti(date) { getStatusParcel (status) {
let d = moment(date).format('D') switch (status) {
let m = moment(date).format('MM') case 'PENDING':
let y = parseInt(moment(date).format('Y')) + 543 return t('waiting_for_pickup');
let new_month = 'ม.ค.'; case 'WAIT_PICKUP':
let new_date = d + ' ' + new_month + ' ' + y; return t('awaiting_payment');
switch (m) { case 'RECEIVE':
case '01': return t('paid');
new_month = 'ม.ค.'; case 'OTHER':
break; return t('other');
case '02': case 'ERROR':
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: default:
new_month = 'ม.ค.'; return t('contact_front_desk');
break;
} }
}
new_date = d + ' ' + new_month + ' ' + y; displayParcelContent (data) {
return new_date; console.log('data >>> ', JSON.parse(data.data))
if(data.parcel_status){
return t('status') + ' : ' + this.getStatusParcel(data.parcel_status)
}
return '';
} }
renderSeparator() { renderSeparator() {
@ -218,11 +350,57 @@ class NotificationScreen extends Component {
if (!this.state.refreshing) return null; if (!this.state.refreshing) return null;
return ( return (
<ActivityIndicator <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 _keyExtractorNewNoti = (item, index) => 'new_noti_'+index
render() { render() {
@ -234,17 +412,30 @@ class NotificationScreen extends Component {
resizeMode: 'cover' resizeMode: 'cover'
}}> }}>
<BackgroundImage> <BackgroundImage>
<ScrollView contentContainerStyle={styles.contentContainer} {/*<ScrollView contentContainerStyle={styles.contentContainer}
refreshControl={ refreshControl={
<RefreshControl <RefreshControl
refreshing={this.state.refreshing} refreshing={this.state.refreshing}
onRefresh={this._onRefresh} onRefresh={this._onRefresh}
/> />
} }
> >*/}
<View style={styles.container}> <View style={styles.container}>
<NavigationEvents
onWillFocus={payload => {
this._onRefresh()
}}
/>
<SafeAreaView style={styles.container}>
<FlatList <FlatList
data={this.state.new_noti} data={this.state.new_noti}
refreshing={true}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
keyExtractor={this._keyExtractorNewNoti} keyExtractor={this._keyExtractorNewNoti}
ListEmptyComponent={() => ListEmptyComponent={() =>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center', margin: 16,padding:16,borderRadius:5,backgroundColor:'white'}}> <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} ItemSeparatorComponent={this.renderSeparator}
ListFooterComponent={this.renderFooter.bind(this)} ListFooterComponent={this.renderFooter.bind(this)}
onEndReachedThreshold={0.01}
onEndReached={this.loadMoreNoti.bind(this)}
renderItem={({item, rowData, index}) => renderItem={({item, rowData, index}) =>
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
this._set_read(item), this._set_read(item)
this.props.navigation.navigate('NewsDetail', { /*this.props.navigation.navigate('NewsDetail', {
news_id: item.source_id, news_id: item.source_id,
getNotification: () => this.getNotification() getNotification: () => this.getNotification()
}) })*/
}} }}
key={index} key={index}
delayPressIn={50} delayPressIn={50}
activeOpacity={0.8} 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}> <View style={styles.viewimages} key={index}>
<Image style={styles.image} //source={{uri: rowData.image}} <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')} defaultSource={require('../../../assets/images/default_small.png')}
/> />
<View style={styles.viewcontainer}> <View style={styles.viewcontainer}>
<Text style={{fontSize: 14, color: '#145EB3', marginBottom: 3,}}> <Text style={{fontSize: 14, color: '#145EB3', marginBottom: 3,}}>
{/*{this.getTypeNoti(item.source_type)}*/} {/*{this.getTypeNoti(item.source_type)}*/}
{ {
item.source && item && item.source_type && this.getTypeNoti(item)
item.source.content_type &&
item.source.content_type == 'general' ? t('latest_news') : t('latest_promotion')
} }
</Text> </Text>
<Text numberOfLines={2} style={{fontSize: 14, color: 'black', marginBottom: 3,}}> <Text
{item.title} numberOfLines={item.source_type === 'payment_success' ? 0 : 3}
style={{fontSize: 14, color: 'black', marginBottom: 3,}}>
{this.getContent(item)}
</Text> </Text>
<Text style={{fontSize: 10, color: 'rgba(0, 0, 0, 0.5)',}}> <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> </Text>
</View> </View>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
} }
/> />
</View> </SafeAreaView>
</ScrollView> </View>
{/*</ScrollView>*/}
</BackgroundImage> </BackgroundImage>
</LinearGradient> </LinearGradient>
) )

View File

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

View File

@ -24,6 +24,12 @@ export default class MessageObjectDetail extends Component {
this.getObjectDetail() 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(){ getObjectDetail(){
getObjectMessageByID(this.state.object_id) getObjectMessageByID(this.state.object_id)
.then(res => { .then(res => {
@ -88,7 +94,7 @@ export default class MessageObjectDetail extends Component {
</View> </View>
<View style={{marginVertical:16,height: 1,backgroundColor:'silver',width: '100%'}}/> <View style={{marginVertical:16,height: 1,backgroundColor:'silver',width: '100%'}}/>
<Text style={styles.textTitle}></Text> <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={{marginVertical:16,height: 1,backgroundColor:'silver',width: '100%'}}/>
<View style={{flexDirection:'row',justifyContent:'space-between'}}> <View style={{flexDirection:'row',justifyContent:'space-between'}}>
<View> <View>

View File

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

View File

@ -2,12 +2,12 @@ import React, { Component } from 'react'
import { import {
View, View,
ScrollView, ScrollView,
Image,
TouchableOpacity, TouchableOpacity,
Platform, Platform,
KeyboardAvoidingView, KeyboardAvoidingView,
Alert Alert
} from 'react-native' } from 'react-native'
import Image from 'react-native-fast-image'
import Icon from '../../components/Icon' import Icon from '../../components/Icon'
import { Picker } from 'native-base' import { Picker } from 'native-base'
import { BackgroundImage_RegisterForm } from '../../components/BackgroundImage_RegisterForm' import { BackgroundImage_RegisterForm } from '../../components/BackgroundImage_RegisterForm'
@ -56,31 +56,42 @@ class EditProfileScreen extends Component {
componentDidMount () { componentDidMount () {
const { navigation } = this.props const { navigation } = this.props
const users_state = navigation.getParam('user', 'NO ITEM') 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) // console.log('check user state ----------- ',users_state)
if(users_state.gender == null || users_state.gender == 'null'){ if(users_state.gender == null || users_state.gender == 'null'){
console.log('NULL'); console.log('NULL');
// this.state.user.show_birth_date = users_state.birth_date;
this.setState({ this.setState({
user: { user: {
gender: 'male', gender: 'male',
...users_state name: users_state.name,
...users_state,
} }
}) })
}else{ }else{
console.log('NOT NULL'); console.log('NOT NULL');
this.setState({ this.setState({
user: users_state user: {
...users_state,
name: users_state.name
}
}) })
} }
this.getProjectList() // this.getProjectList()
} }
getProjectList() { getProjectList() {
project() project()
.then(res => { .then(res => {
if (res.ok) { if (res.ok && res.data && res.data.data) {
return this.setState({ this.setState({
project_list: res.data.data, project_list: res.data.data,
selected_project: res.data.data[0].id selected_project: res.data.data[0].id
}) })
@ -100,23 +111,50 @@ class EditProfileScreen extends Component {
} }
edit_profile () { 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 != null || this.state.user.password != ''){
if(this.state.user.password === this.state.user.confirm_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 => { .then(res => {
this.props.appSetUser(res) if(res.ok){
this.props.navigation.navigate('Profile') 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{ }else{
Alert.alert('รหัสผ่านไม่ถูกต้อง',`รหัสผ่านใหม่ไม่ตรงกับรหัสยืนยัน\nกรุณาลองอีกครั้ง`) Alert.alert('รหัสผ่านไม่ถูกต้อง',`รหัสผ่านใหม่ไม่ตรงกับรหัสยืนยัน\nกรุณาลองอีกครั้ง`)
} }
}else{ }else{
edit_profile(this.state.user).then(res => res.data) edit_profile(this.state.user)
.then(res => { .then(res => {
this.props.appSetUser(res) if(res.ok){
this.props.navigation.navigate('Profile') 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, cropping: true,
includeBase64: true includeBase64: true
}).then(image => { }).then(image => {
// console.log('received base64 image', image) console.log('received base64 image', image)
let image_profile = { let image_profile = {
uri: image.path, uri: image.path,
type: image.mime, type: image.mime,
name: 'image_profile.jpg', name: 'image_profile.jpg',
} }
let image_data = { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height };
this.setState({ this.setState({
image_url: { uri: `data:${image.mime};base64,` + image.data, width: image.width, height: image.height }, image_url: image_profile,
images: null, images: null,
user: { user: {
...this.state.user, ...this.state.user,
profile_image_id: image_profile profile_image_id: image_profile,
profile_image: image_data
} }
}) })
}).catch(e => alert(e)) })
} }
onTakeCamera () { onTakeCamera () {
@ -149,9 +190,12 @@ class EditProfileScreen extends Component {
cropping: true, cropping: true,
width: 300, width: 300,
height: 300, height: 300,
includeExif: true includeExif: true,
includeBase64: true
}).then(image => { }).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 = { let image_profile = {
uri: image.path, uri: image.path,
type: image.mime, type: image.mime,
@ -162,10 +206,11 @@ class EditProfileScreen extends Component {
images: null, images: null,
user: { user: {
...this.state.user, ...this.state.user,
profile_image_id: image_profile profile_image_id: image_profile,
profile_image: image_data
} }
}) })
}).catch(e => alert(e)) })
} }
render () { render () {
@ -173,64 +218,65 @@ class EditProfileScreen extends Component {
const users = navigation.getParam('user', 'NO ITEM') const users = navigation.getParam('user', 'NO ITEM')
// console.log('users :', users); // console.log('users :', users);
return ( return (
<View style={{ flex: 1, backgroundColor: '#00420A' }}> <KeyboardAvoidingView style={{flex:1}}
<KeyboardAvoidingView style={{flex:1}} keyboardVerticalOffset={Platform.OS == 'ios' ? 75 : 0} behavior={Platform.OS == 'ios' ? "padding" : ""} enabled> keyboardVerticalOffset={Platform.OS == 'ios' ? 75 : 0}
behavior={Platform.OS == 'ios' ? 'padding' : ''}
ref={(view) => {this.scrollView = view;}}
>
<View style={{ flex: 1, backgroundColor: '#00420A'}}>
<BackgroundImage_RegisterForm> <BackgroundImage_RegisterForm>
<ScrollView style={{ flexDirection: 'column' }}> <ScrollView style={{ flex: 1, height: '100%' }}>
<LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{ <View style={{ flexDirection: 'column', flex: 1}}>
flex: 1, <View>
width: null, <LinearGradient colors={['#3AA40C', '#2C7C0B']} style={{
height: null, // flex: 1,
resizeMode: 'cover' width: null,
}}> height: null,
<View style={{ flex: 1, paddingVertical: 20, alignItems: 'center' }}> resizeMode: 'cover'
<View style={{ width: '30%' }}> }}>
<TouchableOpacity <View style={{ paddingVertical: 20, alignItems: 'center' }}>
style={{ <View>
backgroundColor: '#FFF', <TouchableOpacity
borderRadius: 50, padding: 5, style={{
justifyContent: 'center', backgroundColor: '#FFF',
alignItems: 'center', borderRadius: 50, padding: 5,
position: 'absolute', justifyContent: 'center',
right: '-5%', alignItems: 'center',
top: '0%', position: 'absolute',
zIndex: 1 right: '0%',
}} top: '0%',
onPress={() => { zIndex: 1
// this.onImagePick() }}
ActionSheet.showActionSheetWithOptions({ onPress={() => {
options: ACTIONSHEET_BUTTONS, // this.onImagePick()
cancelButtonIndex: CANCEL_INDEX, ActionSheet.showActionSheetWithOptions({
// destructiveButtonIndex: DESTRUCTIVE_INDEX, options: ACTIONSHEET_BUTTONS,
// tintColor: 'blue' cancelButtonIndex: CANCEL_INDEX,
}, // destructiveButtonIndex: DESTRUCTIVE_INDEX,
(buttonIndex) => { // tintColor: 'blue'
// console.log('button clicked :', buttonIndex) },
if (buttonIndex == 0) { (buttonIndex) => {
this.onTakeCamera() // console.log('button clicked :', buttonIndex)
} else if (buttonIndex == 1) { if (buttonIndex == 0) {
this.onImagePick() this.onTakeCamera()
} } else if (buttonIndex == 1) {
}) this.onImagePick()
}}> }
<Icon name={'ic_outline_camera'} size={20} color={'#8BC34A'}/> })
</TouchableOpacity> }}>
<Image <Icon name={'ic_outline_camera'} size={20} color={'#8BC34A'}/>
style={{ </TouchableOpacity>
width: 120, <Image
height: 120, style={{width: 120, height: 120, borderRadius: 60, borderColor: 'white', borderWidth: 2}}
borderRadius: 60, source={{ uri: this.state.image_url && this.state.image_url.uri ? this.state.image_url.uri : ''}}
borderColor: 'white', />
borderWidth: 2 </View>
}} </View>
source={this.state.image_url} </LinearGradient>
/>
</View>
</View> </View>
</LinearGradient>
<View style={{ flex: 1, height: '100%' }}> <View style={{ flexDirection: 'column' , padding: 15, paddingTop: 5, paddingBottom: 0,}}>
<View style={{ flex: 1 }}> <View>
<View style={[styles.form]}>
<Text style={styles.headerTitle}>{t('profile')}</Text> <Text style={styles.headerTitle}>{t('profile')}</Text>
<View style={styles.row}> <View style={styles.row}>
<CustomInput <CustomInput
@ -243,7 +289,8 @@ class EditProfileScreen extends Component {
this.setState({ this.setState({
user: { user: {
...this.state.user, ...this.state.user,
name: text name: text,
name_th: text
} }
}) })
}}/> }}/>
@ -264,111 +311,9 @@ class EditProfileScreen extends Component {
}) })
}}/> }}/>
</View> </View>
<View style={styles.row}> {/*<View style={styles.row}>
<View style={styles.row_grow_first}> <View style={styles.row_grow_first}>
<View <View
style={{
flexGrow: 1,
flexDirection: 'row',
height: 40,
maxHeight: 48,
minHeight: 40,
paddingHorizontal: 5,
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 30
}}
>
<View
style={{
justifyContent: 'center',
paddingLeft: 5,
paddingRight: 5
}}
>
<Text
style={{
color: 'white'
}}
>
{t('gender')}
</Text>
</View>
<View style={{ flex: 1,alignItems: Platform.OS == 'ios' ? 'flex-end' : 'stretch'}}>
<Picker
mode="dropdown"
style={{
height: 40,
color: 'white',
}}
textStyle={{color:'white',fontFamily: 'Prompt-Regular',fontSize:14,textAlign:'right'}}
itemStyle={{color:'white',fontFamily: 'Prompt-Regular',fontSize:14}}
itemTextStyle={{color:'black',fontFamily: 'Prompt-Regular',fontSize:14}}
labelName={t('gender')}
placeholder={t('male') +"/"+ t('female')}
selectedValue={this.state.user.gender}
onValueChange={e => {
// console.log('check gender +++++++++++++++ ',e);
this.setState({
user: {
...this.state.user,
gender: e
}
})
}}
>
<Picker.Item label={t('male')} value="male"/>
<Picker.Item label={t('female')} value="female"/>
</Picker>
</View>
</View>
</View>
</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) => {
this.setState({
user: {
...this.state.user,
birth_date: moment(data).format('YYYY-MM-DD')
}
})}}/>
</View>
</View>
<View style={styles.row}>
<CustomInput
style={styles.register_input}
labelColor={'white'}
placeholderTextColor={'white'}
labelName={t('citizen_id')}
value={this.state.user.tax_id}
onChangeText={(text) => {
this.setState({
user: {
...this.state.user,
tax_id: text
}
})
}}/>
</View>
<View style={styles.row}>
<CustomInput
style={styles.register_input}
labelColor={'white'}
placeholderTextColor={'white'}
labelName={t('phone')}
value={this.state.user.mobile}
onChangeText={(text) => {
this.setState({
user: {
...this.state.user,
mobile: text
}
})
}}/>
</View>
<Text style={styles.headerTitle}>{t('accom_info')}</Text>
<View style={styles.row}>
<View
style={{ style={{
flexGrow: 1, flexGrow: 1,
flexDirection: 'row', flexDirection: 'row',
@ -392,114 +337,214 @@ class EditProfileScreen extends Component {
color: 'white' color: 'white'
}} }}
> >
{t('project')} {t('gender')}
</Text> </Text>
</View> </View>
<View style={{ flex: 1 }}> <View style={{ flex: 1,alignItems: Platform.OS == 'ios' ? 'flex-end' : 'stretch'}}>
<Picker <Picker
mode="dropdown"
style={{ style={{
color: 'white',
height: 40, height: 40,
color: 'white',
}} }}
textStyle={{color:'white',fontFamily:'Prompt-Regular',fontSize:14}} textStyle={{color:'white',fontFamily: 'Prompt-Regular',fontSize:14,textAlign:'right'}}
labelName={t('project')} itemStyle={{color:'white',fontFamily: 'Prompt-Regular',fontSize:14}}
placeholder={t('choose_project')} itemTextStyle={{color:'black',fontFamily: 'Prompt-Regular',fontSize:14}}
selectedValue={this.state.project_item} labelName={t('gender')}
placeholder={t('male') +"/"+ t('female')}
selectedValue={this.state.user.gender}
onValueChange={e => { onValueChange={e => {
// console.log('@@@@@@ project selected --------> ',e); // console.log('check gender +++++++++++++++ ',e);
this.setState({ this.setState({
project_name: e.name,
project_item:e,
selected_project: e.id,
user: { user: {
...this.state.user, ...this.state.user,
project: e.code, gender: e
}, }
}, () => {
this.getBuildingList()
}) })
}} }}
> >
{this.state.project_list.map((item,index) => { <Picker.Item label={t('male')} value="male"/>
return <Picker.Item label={item.name} value={item} key={'project_'+index}/> <Picker.Item label={t('female')} value="female"/>
})}
</Picker> </Picker>
</View> </View>
</View> </View>
</View> </View>
</View>*/}
{/*<View style={styles.row}>
<View style={styles.row_grow}>
<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'),
show_birth_date: moment(data).format('YYYY-MM-DD')
}
})}}/>
</View>
</View>*/}
{/*<View style={styles.row}>
<CustomInput
style={styles.register_input}
labelColor={'white'}
placeholderTextColor={'white'}
labelName={t('citizen_id')}
value={this.state.user.tax_id}
onChangeText={(text) => {
this.setState({
user: {
...this.state.user,
tax_id: text
}
})
}}/>
</View>*/}
<View style={styles.row}> <View style={styles.row}>
<CustomInput
style={styles.register_input}
labelColor={'white'}
placeholderTextColor={'white'}
labelName={t('phone')}
value={this.state.user.mobile}
onChangeText={(text) => {
this.setState({
user: {
...this.state.user,
mobile: text
}
})
}}/>
</View>
{/*<Text style={styles.headerTitle}>{t('accom_info')}</Text>*/}
{/*<View style={styles.row}>
<View <View
style={{
flexGrow: 1,
flexDirection: 'row',
height: 40,
maxHeight: 48,
minHeight: 40,
paddingHorizontal: 5,
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 30
}}
>
<View
style={{ style={{
flexGrow: 1, justifyContent: 'center',
flexDirection: 'row', paddingLeft: 5,
height: 40, paddingRight: 5
maxHeight: 48, }}
minHeight: 40, >
paddingHorizontal: 5, <Text
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 30
}}>
<View
style={{ style={{
justifyContent: 'center', color: 'white'
paddingLeft: 5, }}
paddingRight: 5 >
}}> {t('project')}
<Text </Text>
style={{
color: 'white'
}}>
{t('building')}
</Text>
</View>
<View style={{ flex: 1 }}>
<Picker
// mode="dropdown"
style={{
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')}
selectedValue={this.state.user.building != null && this.state.user.building}
onValueChange={e => {
this.setState({
user: {
...this.state.user,
building: e
}
})
}}>
{this.state.building_list.length > 0 && this.state.building_list.map((item,index) => {
return <Picker.Item label={item.room_build} value={item.room_build} key={'building_'+index}/>
})}
</Picker>
</View>
</View> </View>
<View style={styles.row_grow}> <View style={{ flex: 1 }}>
<CustomInput <Picker
style={styles.register_input} style={{
labelColor={'white'} color: 'white',
placeholderTextColor={'white'} height: 40,
labelName={t('room2')} }}
placeholder={t('room_no')} textStyle={{color:'white',fontFamily:'Prompt-Regular',fontSize:14}}
placeholderTextColor={'#FFFFFF40'} labelName={t('project')}
value={this.state.user.room} placeholder={t('choose_project')}
onChangeText={(text) => { selectedValue={this.state.project_item}
onValueChange={e => {
// console.log('@@@@@@ project selected --------> ',e);
this.setState({
project_name: e.name,
project_item:e,
selected_project: e.id,
user: {
...this.state.user,
project: e.code,
},
}, () => {
this.getBuildingList()
})
}}
>
{this.state.project_list.map((item,index) => {
return <Picker.Item label={item.name} value={item} key={'project_'+index}/>
})}
</Picker>
</View>
</View>
</View>*/}
{/*<View style={styles.row}>
<View
style={{
flexGrow: 1,
flexDirection: 'row',
height: 40,
maxHeight: 48,
minHeight: 40,
paddingHorizontal: 5,
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 30
}}>
<View
style={{
justifyContent: 'center',
paddingLeft: 5,
paddingRight: 5
}}>
<Text
style={{
color: 'white'
}}>
{t('building')}
</Text>
</View>
<View style={{ flex: 1 }}>
<Picker
// mode="dropdown"
style={{
color: 'white',
height: 40,
}}
textStyle={{color:'white',fontFamily:'Prompt-Regular',fontSize:14}}
labelName={t('building')}
placeholder={t('choose_project')}
selectedValue={this.state.user.building != null && this.state.user.building}
onValueChange={e => {
this.setState({ this.setState({
user: { user: {
...this.state.user, ...this.state.user,
room: text building: e
} }
}) })
}}/> }}>
{this.state.building_list.map((item,index) => {
return <Picker.Item label={item.room_build} value={item.room_build} key={'building_'+index}/>
})}
</Picker>
</View> </View>
</View> </View>
<View style={styles.row_grow}>
<CustomInput
style={styles.register_input}
labelColor={'white'}
placeholderTextColor={'white'}
labelName={t('room2')}
placeholder={t('room_no')}
placeholderTextColor={'#FFFFFF40'}
value={this.state.user.room}
onChangeText={(text) => {
this.setState({
user: {
...this.state.user,
room: text
}
})
}}/>
</View>
</View>*/}
<Text style={styles.headerTitle}>{t('change_password')}</Text> <Text style={styles.headerTitle}>{t('change_password')}</Text>
<View> <View>
<View style={styles.row}> <View style={styles.row}>
@ -540,11 +585,14 @@ class EditProfileScreen extends Component {
}}/> }}/>
</View> </View>
</View> </View>
</View>
<View>
<View style={styles.buttons}> <View style={styles.buttons}>
<View style={styles.row_grow}> <View style={styles.row_grow}>
<CustomButton style={styles.btn_next_register} title={t('complete')} <CustomButton style={styles.btn_next_register} title={t('complete')}
sizeText={14} sizeText={14}
onPress={this.edit_profile} onPress={this.edit_profile}
/> />
</View> </View>
</View> </View>
@ -553,8 +601,8 @@ class EditProfileScreen extends Component {
</View> </View>
</ScrollView> </ScrollView>
</BackgroundImage_RegisterForm> </BackgroundImage_RegisterForm>
</KeyboardAvoidingView>
</View> </View>
</KeyboardAvoidingView>
) )
} }
} }
@ -609,10 +657,10 @@ const styles = {
backgroundColor: 'rgba(255,255,255,0.3)', backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 30, borderRadius: 30,
} }
} };
const mapDisPatchToProps = state => { const mapDisPatchToProps = state => {
return state.app return state.app
} };
const setUser = dispatch => bindActionCreators({ appSetDevice, appSetUser, appCleanUser }, dispatch) const setUser = dispatch => bindActionCreators({ appSetDevice, appSetUser, appCleanUser }, dispatch)
export default connect(mapDisPatchToProps, setUser)(EditProfileScreen) export default connect(mapDisPatchToProps, setUser)(EditProfileScreen)

View File

@ -23,6 +23,7 @@ class ProfileScreen extends Component {
isLoading: false, isLoading: false,
user:{}, user:{},
room:null, room:null,
profileImage: require('../../../assets/images/profile.png')
} }
this.getUserData = this.getUserData.bind(this) this.getUserData = this.getUserData.bind(this)
} }
@ -42,10 +43,18 @@ class ProfileScreen extends Component {
.then(res => { .then(res => {
// console.log('user profile -------> ',res); // console.log('user profile -------> ',res);
if(res.ok){ 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({ this.setState({
isLoading: false, isLoading: false,
user: res.data.user, 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{ }else{
this.setState({ 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() { refreshPage() {
window.location.reload(false); window.location.reload(false);
} }
@ -69,6 +103,7 @@ class ProfileScreen extends Component {
}}> }}>
<NavigationEvents <NavigationEvents
onDidFocus={() => { onDidFocus={() => {
console.log('getUserData');
this.getUserData() this.getUserData()
}} }}
/> />
@ -80,7 +115,7 @@ class ProfileScreen extends Component {
}}> }}>
<Image <Image
style={{ width: 120, height: 120, borderRadius: 60, borderColor: 'white', borderWidth: 2 }} style={{ width: 120, height: 120, borderRadius: 60, borderColor: 'white', borderWidth: 2 }}
source={require('../../../assets/images/profile.png')} source={this.state.profileImage}
/> />
</View> </View>
<View style={{ flex: 1, padding: 15, }}> <View style={{ flex: 1, padding: 15, }}>
@ -89,7 +124,7 @@ class ProfileScreen extends Component {
<Text style={{ color: '#8BC34A', marginBottom: 10 }}>{t('profile')}</Text> <Text style={{ color: '#8BC34A', marginBottom: 10 }}>{t('profile')}</Text>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('category')}</Text> <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>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('name')}</Text> <Text style={styles.text_field_style}>{t('name')}</Text>
@ -97,7 +132,7 @@ class ProfileScreen extends Component {
</View> </View>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('email')}</Text> <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>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('phone2')}</Text> <Text style={styles.text_field_style}>{t('phone2')}</Text>
@ -109,11 +144,11 @@ class ProfileScreen extends Component {
</View> </View>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('gender')}</Text> <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>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<Text style={styles.text_field_style}>{t('birth_date')}</Text> <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>
</View> </View>
{ {
@ -144,18 +179,9 @@ class ProfileScreen extends Component {
<View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}> <View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}>
<Button block style={{ backgroundColor: '#145EB3', marginHorizontal: 15 }} <Button block style={{ backgroundColor: '#145EB3', marginHorizontal: 15 }}
onPress={() => { onPress={() => {
setTimeout( () => { setTimeout( () => {
loginWithFacebook() loginWithFacebook(this.connectFBSuccess)
setTimeout( () => {
this.state.user.fb_is_link = 't'
this.props.navigation.navigate('Profile',{user:this.state.user})
Alert.alert('Connect with Facebook Success')
},4000);
},1000); },1000);
}} > }} >
<Text style={{ color: '#ffffff', fontSize: 14 }}>{t('connect_facebook')}</Text> <Text style={{ color: '#ffffff', fontSize: 14 }}>{t('connect_facebook')}</Text>
</Button> </Button>
@ -164,18 +190,7 @@ class ProfileScreen extends Component {
<View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}> <View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}>
<Button block style={{ backgroundColor: '#145EB3', marginHorizontal: 15 }} <Button block style={{ backgroundColor: '#145EB3', marginHorizontal: 15 }}
onPress={() => { onPress={() => {
disconnectWithFacebook(this.disConnectFBSuccess);
disconnectWithFacebook();
setTimeout( () => {
this.state.user.fb_is_link = 'f'
//alert("Disconnected!")
this.props.navigation.replace('Profile',{user:this.state.user})
},3000);
}} }}
> >
<Text style={{ color: '#ffffff', fontSize: 14 }}>{t('disconnect_facebook')}</Text> <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)' }}> <View style={{ flexGrow: 0.5, justifyContent: 'flex-end', backgroundColor: 'rgba(0,0,0,0)' }}>
<Button block style={{ backgroundColor: '#145EB3', margin:15 }} <Button block style={{ backgroundColor: '#145EB3', margin:15 }}
onPress={() => { this.props.navigation.navigate('EditProfile',{ 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> <Text style={{ color: '#ffffff', fontSize: 14 }}><Icon name={'ic_edit'} size={15}/> {t('edit_profile')} </Text>
</Button> </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