tum преди 2 години
родител
ревизия
3a8e79ec08
променени са 10 файла, в които са добавени 310 реда и са изтрити 14 реда
  1. 1 0
      ios/App/Podfile
  2. 7 1
      ios/App/Podfile.lock
  3. 9 0
      package-lock.json
  4. 1 0
      package.json
  5. 39 0
      src/components/LoginForm.vue
  6. 24 3
      src/composable/settings.ts
  7. 5 0
      src/router/index.ts
  8. 80 9
      src/views/ProfilePage.vue
  9. 143 0
      src/views/ResetPassPage.vue
  10. 1 1
      src/views/SignupPage.vue

+ 1 - 0
ios/App/Podfile

@@ -19,6 +19,7 @@ def capacitor_pods
19 19
   pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications'
20 20
   pod 'CapacitorShare', :path => '../../node_modules/@capacitor/share'
21 21
   pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
22
+  pod 'CapgoInappbrowser', :path => '../../node_modules/@capgo/inappbrowser'
22 23
   pod 'CodetrixStudioCapacitorGoogleAuth', :path => '../../node_modules/@codetrix-studio/capacitor-google-auth'
23 24
 end
24 25
 

+ 7 - 1
ios/App/Podfile.lock

@@ -26,6 +26,8 @@ PODS:
26 26
     - Capacitor
27 27
   - CapacitorStatusBar (5.0.6):
28 28
     - Capacitor
29
+  - CapgoInappbrowser (1.2.19):
30
+    - Capacitor
29 31
   - CodetrixStudioCapacitorGoogleAuth (0.0.1):
30 32
     - Capacitor
31 33
     - GoogleSignIn (~> 6.2.4)
@@ -109,6 +111,7 @@ DEPENDENCIES:
109 111
   - "CapacitorPushNotifications (from `../../node_modules/@capacitor/push-notifications`)"
110 112
   - "CapacitorShare (from `../../node_modules/@capacitor/share`)"
111 113
   - "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
114
+  - "CapgoInappbrowser (from `../../node_modules/@capgo/inappbrowser`)"
112 115
   - "CodetrixStudioCapacitorGoogleAuth (from `../../node_modules/@codetrix-studio/capacitor-google-auth`)"
113 116
   - Firebase/Messaging
114 117
 
@@ -153,6 +156,8 @@ EXTERNAL SOURCES:
153 156
     :path: "../../node_modules/@capacitor/share"
154 157
   CapacitorStatusBar:
155 158
     :path: "../../node_modules/@capacitor/status-bar"
159
+  CapgoInappbrowser:
160
+    :path: "../../node_modules/@capgo/inappbrowser"
156 161
   CodetrixStudioCapacitorGoogleAuth:
157 162
     :path: "../../node_modules/@codetrix-studio/capacitor-google-auth"
158 163
 
@@ -168,6 +173,7 @@ SPEC CHECKSUMS:
168 173
   CapacitorPushNotifications: b31e326c6e4eb216a622041d6ca21a973f34943f
169 174
   CapacitorShare: cd41743331cb71d217c029de54b681cbd91e0fcc
170 175
   CapacitorStatusBar: 565c0a1ebd79bb40d797606a8992b4a105885309
176
+  CapgoInappbrowser: a1d7b17df89659ece82ad102a0775786c6166512
171 177
   CodetrixStudioCapacitorGoogleAuth: fcce058390347c1ce5d8ac4764bdf1f5c1ee233b
172 178
   FBAEMKit: af2972f39bb0f3f7c45998f435b007833c32ffb2
173 179
   FBSDKCoreKit: 19e2e18b3be578d7a51fed8fdd8c152bef0b9511
@@ -186,6 +192,6 @@ SPEC CHECKSUMS:
186 192
   nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
187 193
   PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
188 194
 
189
-PODFILE CHECKSUM: b5088696bfe6f308f08046e80f0b75910bd6bc77
195
+PODFILE CHECKSUM: e092ee1cde7b2ee2c683b5d37e9df1aa750682e4
190 196
 
191 197
 COCOAPODS: 1.12.1

+ 9 - 0
package-lock.json

@@ -18,6 +18,7 @@
18 18
         "@capacitor/push-notifications": "^5.1.0",
19 19
         "@capacitor/share": "^5.0.6",
20 20
         "@capacitor/status-bar": "5.0.6",
21
+        "@capgo/inappbrowser": "^1.2.19",
21 22
         "@codetrix-studio/capacitor-google-auth": "^3.3.4",
22 23
         "@ionic/vue": "^7.5.4",
23 24
         "@ionic/vue-router": "^7.5.4",
@@ -1940,6 +1941,14 @@
1940 1941
         "@capacitor/core": "^5.0.0"
1941 1942
       }
1942 1943
     },
1944
+    "node_modules/@capgo/inappbrowser": {
1945
+      "version": "1.2.19",
1946
+      "resolved": "https://registry.npmjs.org/@capgo/inappbrowser/-/inappbrowser-1.2.19.tgz",
1947
+      "integrity": "sha512-Koyg3a7D2lpccZfW+CZ9JEKE5to5iGbi12DFgPN+TOmMuJLCVAYcWVsR9Q4nXIQCg5f4ExCz7XfBrHNKUBULrQ==",
1948
+      "peerDependencies": {
1949
+        "@capacitor/core": "^5.0.0"
1950
+      }
1951
+    },
1943 1952
     "node_modules/@codetrix-studio/capacitor-google-auth": {
1944 1953
       "version": "3.3.4",
1945 1954
       "resolved": "https://registry.npmjs.org/@codetrix-studio/capacitor-google-auth/-/capacitor-google-auth-3.3.4.tgz",

+ 1 - 0
package.json

@@ -22,6 +22,7 @@
22 22
     "@capacitor/push-notifications": "^5.1.0",
23 23
     "@capacitor/share": "^5.0.6",
24 24
     "@capacitor/status-bar": "5.0.6",
25
+    "@capgo/inappbrowser": "^1.2.19",
25 26
     "@codetrix-studio/capacitor-google-auth": "^3.3.4",
26 27
     "@ionic/vue": "^7.5.4",
27 28
     "@ionic/vue-router": "^7.5.4",

+ 39 - 0
src/components/LoginForm.vue

@@ -0,0 +1,39 @@
1
+<template>
2
+  <div class='ion-padding'>
3
+          <ion-input label="Username"  v-model="username" label-placement="floating" fill="outline" placeholder="Example, john"
4
+                                                                                                ></ion-input>
5
+          <ion-input label="Password" label-placement='floating' fill='outline' v-model="password" type="password" placeholder="Password"></ion-input>
6
+          <ion-text color="danger" v-if="formError">{{ formError }}</ion-text>
7
+          <ion-button @click="login" class=' ion-margin-top' expand='full'>Login</ion-button>
8
+  </div>
9
+</template>
10
+<script setup>
11
+
12
+import {  IonButton, IonList,IonLabel,
13
+IonItem, IonInput, toastController, useIonRouter, IonText } from '@ionic/vue';
14
+import { defineComponent, onMounted } from 'vue';
15
+
16
+import { userLogin } from '@/composable/settings';
17
+
18
+import { ref } from 'vue';
19
+
20
+const username = ref()
21
+const password = ref()
22
+const formError = ref(null)
23
+
24
+const emit = defineEmits(['userLogin'])
25
+onMounted( () => {
26
+  
27
+})
28
+const login = async () => {
29
+  try{
30
+    const data = await userLogin(username.value, password.value)
31
+    emit('userLogin', {data:data})
32
+  }
33
+  catch(error){
34
+    console.info("error ", error)
35
+    formError.value = error.response.data.non_field_errors[0]
36
+    emit('userLogin', {error:error})
37
+  }
38
+}
39
+</script>

+ 24 - 3
src/composable/settings.ts

@@ -1,6 +1,6 @@
1 1
 import { CapacitorHttp } from '@capacitor/core';
2
-import Axios from "axios";
3
-//import axios from "axios";
2
+//import Axios from "axios";
3
+import axios from "axios";
4 4
 import { setupCache } from 'axios-cache-interceptor';
5 5
 
6 6
 
@@ -12,7 +12,7 @@ export const TOKEN = '173cb9e357a861abd91e8008fab9246e0cc116af'
12 12
 export const BASE_URL = 'http://localhost:8020/'
13 13
 //export const BASE_URL = 'https://www.tigermuaythai.live/'
14 14
 
15
-const axios = setupCache(Axios); 
15
+//const axios = setupCache(Axios); 
16 16
 //
17 17
 //axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
18 18
 //axios.defaults.xsrfCookieName = "csrftoken";
@@ -271,6 +271,16 @@ export const facebookLogin = async(access_token) => {
271 271
   console.log("facebook login = ", data)
272 272
   return data
273 273
 }
274
+export const userLogin = async(username, password) => {
275
+
276
+  const { data } = await axios.post(BASE_URL + 'dj-rest-auth/login/',{username: username, password: password}, {
277
+    headers: {
278
+      'Content-Type': 'application/json', 
279
+    }
280
+  })
281
+  console.log("login =  data", data)
282
+  return data
283
+}
274 284
 
275 285
 export const logout = async() => {
276 286
 
@@ -312,3 +322,14 @@ export const restSignup = async (username, email, pass1, pass2) => {
312 322
   })
313 323
   return data
314 324
 }
325
+export const resetPassword = async (email) => {
326
+  console.info(" email ", email)
327
+  const { data } = await axios.post(BASE_URL + 'password-reset/',{
328
+    email: email,
329
+  }, {
330
+    headers: {
331
+      'Content-Type': 'application/json', 
332
+    }
333
+  })
334
+  return data
335
+}

+ 5 - 0
src/router/index.ts

@@ -57,6 +57,11 @@ const routes: Array<RouteRecordRaw> = [
57 57
         component: () => import('@/views/SignupPage.vue')
58 58
       },
59 59
       {
60
+        path: 'resetpass/',
61
+        name: 'resetpass', 
62
+        component: () => import('@/views/ResetPassPage.vue')
63
+      },
64
+      {
60 65
         path: 'post_detail/:id/',
61 66
         name: 'post_detail', 
62 67
         component: () => import('@/views/PostDetailPage.vue')

+ 80 - 9
src/views/ProfilePage.vue

@@ -2,31 +2,67 @@
2 2
    <ion-page>
3 3
     <ion-header>
4 4
       <ion-toolbar>
5
-        <ion-title>Listen now</ion-title>
5
+        <ion-title>User Profile</ion-title>
6 6
       </ion-toolbar>
7 7
     </ion-header>
8 8
     <ion-content>
9
-      <div class="example-content">Listen now content</div>
9
+      <!--
10 10
       <ion-button @click='clear'>Clear Pref</ion-button>
11
-      <ion-button @click='btnLogout'>Btn Logout</ion-button>
12
-      <ion-button router-link="/tabs/signup">Signup</ion-button>
11
+      <ion-button @click='btnLogout'>Btn Logout</ion-button> -->
13 12
       <template v-if="isLogin">
14
-      <ion-button @click='fbLogout'>Logout</ion-button>
13
+        <ion-list>
14
+          <ion-list-header>
15
+            <ion-label>Notifications</ion-label>
16
+          </ion-list-header>
17
+          <ion-item>
18
+            <ion-toggle v-model="liveNoti">Receive Live Notifications</ion-toggle>
19
+          </ion-item>
20
+          <ion-item>
21
+            <ion-toggle v-model="newsNoti">Receive News Update</ion-toggle>
22
+          </ion-item>
23
+          <ion-list-header>
24
+            <ion-label>Martial Arts, I Love</ion-label>
25
+          </ion-list-header>
26
+        </ion-list>
27
+      <ion-button @click='fbLogout' expand='full'>Logout</ion-button>
15 28
       </template>
16 29
       <template v-else>
17
-        <ion-button @click='fbLogin'>Facebook Login</ion-button>
18
-        <ion-button @click='ggLogin'>Google Login</ion-button>
30
+        <LoginForm @user-login="userLogin" />
31
+        <ion-grid>
32
+            <ion-row>
33
+              <ion-col size=6>
34
+                <ion-button fill='clear' router-link="/tabs/signup">Signup</ion-button>
35
+              </ion-col>
36
+              <ion-col  size=6>
37
+                  <ion-button @click="openReset" fill='clear' class='ion-float-right'>Reset Password</ion-button>
38
+              </ion-col>
39
+            </ion-row>
40
+        </ion-grid>
41
+        <ion-grid>
42
+          <ion-row class='ion-justify-content-center'>
43
+            <ion-col size=6>
44
+              <ion-button @click='fbLogin' expand='full'>Facebook Login</ion-button>
45
+            </ion-col>
46
+            <ion-col size=6>
47
+              <ion-button @click='ggLogin' expand='full'>Google Login</ion-button>
48
+            </ion-col>
49
+          </ion-row>
50
+        </ion-grid>
19 51
       </template>
20 52
     </ion-content>
21 53
   </ion-page>
22 54
 </template>
23 55
 
24 56
 <script setup lang="ts">
25
-import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonButton, onIonViewWillEnter } from '@ionic/vue';
57
+import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonButton, onIonViewWillEnter, IonRow, IonCol, IonGrid, IonToggle, IonLabel } from '@ionic/vue';
26 58
 import ExploreContainer from '@/components/ExploreContainer.vue';
59
+import LoginForm from '@/components/LoginForm.vue';
27 60
 import { defineComponent, onMounted } from 'vue';
28 61
 import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
29
-import { facebookLogin, setUserToken, logout, clearPref } from '@/composable/settings';
62
+import { facebookLogin, setUserToken, logout, clearPref, BASE_URL } from '@/composable/settings';
63
+import { InAppBrowser } from '@capgo/inappbrowser'
64
+
65
+
30 66
 
31 67
 onMounted(() => {
32 68
   GoogleAuth.initialize();
@@ -47,6 +83,29 @@ const FACEBOOK_PERMISSIONS = [
47 83
 ];
48 84
 
49 85
 const isLogin = ref(false)
86
+const liveNoti = ref(true)
87
+const favCourseNoti = ref(true)
88
+const newsNoti = ref(true)
89
+
90
+
91
+const openReset = async () => {
92
+  console.log("open Reset")
93
+  const browser = await InAppBrowser.open({ url: BASE_URL + "accounts/password_reset/" });
94
+  console.info("bw ", browser)
95
+  InAppBrowser.addListener("urlChangeEvent", urlChange)
96
+}
97
+
98
+const urlChange = (event) => {
99
+  console.info("url change ", event)
100
+  if(event.url.includes("/accounts/password_reset/done/")) {
101
+    setTimeout(async () => {
102
+      InAppBrowser.close()
103
+    }, 3000)
104
+  }else {
105
+  
106
+  }
107
+  //accounts/password_reset/done/
108
+}
50 109
 
51 110
 const ggLogin = async () => {
52 111
   const response = await GoogleAuth.signIn();
@@ -120,4 +179,16 @@ const ggCheckLogin = async() => {
120 179
 const clear = async() => {
121 180
   await clearPref()
122 181
 }
182
+const userLogin = async (data) => {
183
+  console.info("user login ", data)
184
+  if(data.error) {
185
+    console.log("ERROR")
186
+  }else {
187
+    console.log("Success")
188
+    await setUserToken(data.key)
189
+    
190
+    // Login successful.
191
+    isLogin.value = true
192
+  }
193
+}
123 194
 </script>

+ 143 - 0
src/views/ResetPassPage.vue

@@ -0,0 +1,143 @@
1
+<template>
2
+  <ion-page>
3
+    <ion-header>
4
+      <ion-toolbar>
5
+        <ion-buttons slot="start">
6
+          <ion-back-button></ion-back-button>
7
+        </ion-buttons>
8
+        <ion-title>
9
+          Reset Password
10
+        </ion-title>
11
+      </ion-toolbar>
12
+    </ion-header>
13
+    <ion-content class='ion-padding'>
14
+
15
+          <ion-input label="Email" label-placement="floating" v-model="email" fill="outline" type="email" placeholder="Example, hello@gmail.com"></ion-input>
16
+          <ion-button @click="resetPasswordBtn">Reset Password</ion-button>
17
+          <ion-input label="Username"  ref="username" label-placement="floating" fill="outline" placeholder="Example, john"
18
+                                                                                                ></ion-input>
19
+          <ion-input label="Password" label-placement='floating' fill='outline' ref="password" type="password" placeholder="Password"></ion-input>
20
+          <ion-input label="Password Confirmation" label-placement='floating' fill='outline' ref="password2" type="password" placeholder="Password Confirmation"></ion-input>
21
+          <ion-text color="danger" v-if="formError">{{ formError }}</ion-text>
22
+          <ion-button @click="signup" class=' ion-margin-top'>Signup</ion-button>
23
+    </ion-content>
24
+  </ion-page>
25
+</template>
26
+
27
+<script setup lang="ts">
28
+import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonButton, onIonViewWillEnter, IonList, IonSearchbar, IonLabel,
29
+IonItem, IonBackButton, IonProgressBar, IonButtons, IonInfiniteScroll,
30
+    IonInfiniteScrollContent, InfiniteScrollCustomEvent, IonInput, toastController, useIonRouter } from '@ionic/vue';
31
+import { defineComponent, onMounted } from 'vue';
32
+import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
33
+import { searchMat, callUrl,restSignup, resetPassword } from '@/composable/settings';
34
+
35
+import { ref } from 'vue';
36
+import SearchItem from '@/components/SearchItem.vue';
37
+
38
+const results = ref();
39
+const is_empty = ref(false);
40
+const processing = ref(false)
41
+let next_url = null
42
+
43
+const username = ref(null)
44
+const password = ref(null)
45
+const password2 = ref(null)
46
+const email = ref(null)
47
+const input = ref(null)
48
+const ionRouter = useIonRouter();
49
+const formError = ref(null)
50
+
51
+
52
+const resetPasswordBtn = async() => {
53
+  console.log("reset password")
54
+  try{
55
+    const data = await resetPassword(email.value)
56
+    console.info(data)
57
+  }catch(error) {
58
+    console.info(error)
59
+  }
60
+}
61
+const signup = async () => { 
62
+  clearError(username)
63
+  clearError(email)
64
+  clearError(password)
65
+  clearError(password2)
66
+  formError.value = null
67
+  try {
68
+    console.log("username = ", username.value.$el.value)
69
+    const data = await restSignup(username.value.$el.value, email.value.$el.value, password.value.$el.value, password2.value.$el.value)
70
+    console.log(data)
71
+    await presentToast("Sign up successful", "top")
72
+    ionRouter.navigate('/tabs/tab4', 'forward', 'replace');
73
+  }catch( err ) {
74
+    console.log("-- error --")
75
+    console.log(err)
76
+    for(const [k,v] of Object.entries(err.response.data))  {
77
+      if( k == "username" ){
78
+        showError(username, v[0])
79
+      }
80
+      if( k == "email" ){
81
+        showError(email, v[0])
82
+      }
83
+      if( k == "password1" ){
84
+        showError(password, v[0])
85
+      }
86
+      if( k == "password2" ){
87
+        showError(password2, v[0])
88
+      }
89
+      if( k == "non_field_errors" ) {
90
+        formError.value = v[0]
91
+      }
92
+    }
93
+  }
94
+}
95
+
96
+const showError = (obj, error) => {
97
+  obj.value.$el.errorText = error
98
+  obj.value.$el.classList.add('ion-invalid')
99
+  obj.value.$el.classList.add('ion-touched');
100
+}
101
+const clearError = (obj) => {
102
+  obj.value.$el.classList.remove("ion-valid")
103
+  obj.value.$el.classList.remove("ion-invalid")
104
+}
105
+
106
+const validateEmail = (email) => {
107
+        return email.match(
108
+          /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
109
+        );
110
+      }
111
+
112
+  const validate = (ev) => {
113
+        const value = ev.target.value;
114
+
115
+        input.value.$el.classList.remove('ion-valid');
116
+        input.value.$el.classList.remove('ion-invalid');
117
+
118
+        if (value === '') return;
119
+
120
+        validateEmail(value)
121
+          ? input.value.$el.classList.add('ion-valid')
122
+          : input.value.$el.classList.add('ion-invalid');
123
+      }
124
+
125
+const markTouched = () => {
126
+  input.value.$el.classList.add('ion-touched');
127
+}
128
+const markTouched2 = () => {
129
+  username.value.$el.classList.add('ion-touched');
130
+}
131
+const presentToast = async (msg, position: 'top' | 'middle' | 'bottom') => {
132
+  console.log("present toast")
133
+  const toast = await toastController.create({
134
+    message: msg,
135
+    duration: 3000,
136
+    position: position,
137
+    positionAnchor: "header",
138
+    color: "success"
139
+  });
140
+
141
+  await toast.present();
142
+}
143
+</script>

+ 1 - 1
src/views/SignupPage.vue

@@ -18,7 +18,7 @@
18 18
           <ion-input label="Password" label-placement='floating' fill='outline' ref="password" type="password" placeholder="Password"></ion-input>
19 19
           <ion-input label="Password Confirmation" label-placement='floating' fill='outline' ref="password2" type="password" placeholder="Password Confirmation"></ion-input>
20 20
           <ion-text color="danger" v-if="formError">{{ formError }}</ion-text>
21
-          <ion-button @click="signup" class=' ion-margin-top'>Signup</ion-button>
21
+          <ion-button @click="signup" expand='full' class=' ion-margin-top'>Signup</ion-button>
22 22
     </ion-content>
23 23
   </ion-page>
24 24
 </template>