tum 2 年之前
父节点
当前提交
3a8e79ec08

+ 1 - 0
ios/App/Podfile

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

+ 7 - 1
ios/App/Podfile.lock

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

+ 9 - 0
package-lock.json

18
         "@capacitor/push-notifications": "^5.1.0",
18
         "@capacitor/push-notifications": "^5.1.0",
19
         "@capacitor/share": "^5.0.6",
19
         "@capacitor/share": "^5.0.6",
20
         "@capacitor/status-bar": "5.0.6",
20
         "@capacitor/status-bar": "5.0.6",
21
+        "@capgo/inappbrowser": "^1.2.19",
21
         "@codetrix-studio/capacitor-google-auth": "^3.3.4",
22
         "@codetrix-studio/capacitor-google-auth": "^3.3.4",
22
         "@ionic/vue": "^7.5.4",
23
         "@ionic/vue": "^7.5.4",
23
         "@ionic/vue-router": "^7.5.4",
24
         "@ionic/vue-router": "^7.5.4",
1940
         "@capacitor/core": "^5.0.0"
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
     "node_modules/@codetrix-studio/capacitor-google-auth": {
1952
     "node_modules/@codetrix-studio/capacitor-google-auth": {
1944
       "version": "3.3.4",
1953
       "version": "3.3.4",
1945
       "resolved": "https://registry.npmjs.org/@codetrix-studio/capacitor-google-auth/-/capacitor-google-auth-3.3.4.tgz",
1954
       "resolved": "https://registry.npmjs.org/@codetrix-studio/capacitor-google-auth/-/capacitor-google-auth-3.3.4.tgz",

+ 1 - 0
package.json

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

+ 39 - 0
src/components/LoginForm.vue

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
 import { CapacitorHttp } from '@capacitor/core';
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
 import { setupCache } from 'axios-cache-interceptor';
4
 import { setupCache } from 'axios-cache-interceptor';
5
 
5
 
6
 
6
 
12
 export const BASE_URL = 'http://localhost:8020/'
12
 export const BASE_URL = 'http://localhost:8020/'
13
 //export const BASE_URL = 'https://www.tigermuaythai.live/'
13
 //export const BASE_URL = 'https://www.tigermuaythai.live/'
14
 
14
 
15
-const axios = setupCache(Axios); 
15
+//const axios = setupCache(Axios); 
16
 //
16
 //
17
 //axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
17
 //axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
18
 //axios.defaults.xsrfCookieName = "csrftoken";
18
 //axios.defaults.xsrfCookieName = "csrftoken";
271
   console.log("facebook login = ", data)
271
   console.log("facebook login = ", data)
272
   return data
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
 export const logout = async() => {
285
 export const logout = async() => {
276
 
286
 
312
   })
322
   })
313
   return data
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
         component: () => import('@/views/SignupPage.vue')
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
         path: 'post_detail/:id/',
65
         path: 'post_detail/:id/',
61
         name: 'post_detail', 
66
         name: 'post_detail', 
62
         component: () => import('@/views/PostDetailPage.vue')
67
         component: () => import('@/views/PostDetailPage.vue')

+ 80 - 9
src/views/ProfilePage.vue

2
    <ion-page>
2
    <ion-page>
3
     <ion-header>
3
     <ion-header>
4
       <ion-toolbar>
4
       <ion-toolbar>
5
-        <ion-title>Listen now</ion-title>
5
+        <ion-title>User Profile</ion-title>
6
       </ion-toolbar>
6
       </ion-toolbar>
7
     </ion-header>
7
     </ion-header>
8
     <ion-content>
8
     <ion-content>
9
-      <div class="example-content">Listen now content</div>
9
+      <!--
10
       <ion-button @click='clear'>Clear Pref</ion-button>
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
       <template v-if="isLogin">
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
       </template>
28
       </template>
16
       <template v-else>
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
       </template>
51
       </template>
20
     </ion-content>
52
     </ion-content>
21
   </ion-page>
53
   </ion-page>
22
 </template>
54
 </template>
23
 
55
 
24
 <script setup lang="ts">
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
 import ExploreContainer from '@/components/ExploreContainer.vue';
58
 import ExploreContainer from '@/components/ExploreContainer.vue';
59
+import LoginForm from '@/components/LoginForm.vue';
27
 import { defineComponent, onMounted } from 'vue';
60
 import { defineComponent, onMounted } from 'vue';
28
 import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
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
 onMounted(() => {
67
 onMounted(() => {
32
   GoogleAuth.initialize();
68
   GoogleAuth.initialize();
47
 ];
83
 ];
48
 
84
 
49
 const isLogin = ref(false)
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
 const ggLogin = async () => {
110
 const ggLogin = async () => {
52
   const response = await GoogleAuth.signIn();
111
   const response = await GoogleAuth.signIn();
120
 const clear = async() => {
179
 const clear = async() => {
121
   await clearPref()
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
 </script>
194
 </script>

+ 143 - 0
src/views/ResetPassPage.vue

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
           <ion-input label="Password" label-placement='floating' fill='outline' ref="password" type="password" placeholder="Password"></ion-input>
18
           <ion-input label="Password" label-placement='floating' fill='outline' ref="password" type="password" placeholder="Password"></ion-input>
19
           <ion-input label="Password Confirmation" label-placement='floating' fill='outline' ref="password2" type="password" placeholder="Password Confirmation"></ion-input>
19
           <ion-input label="Password Confirmation" label-placement='floating' fill='outline' ref="password2" type="password" placeholder="Password Confirmation"></ion-input>
20
           <ion-text color="danger" v-if="formError">{{ formError }}</ion-text>
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
     </ion-content>
22
     </ion-content>
23
   </ion-page>
23
   </ion-page>
24
 </template>
24
 </template>