66 </v-btn >
77 <v-toolbar-title >
88 <span v-if =" $store.getters.hasThread" >
9- {{ $store.getters.getThread.contact }}
9+ {{ $store.getters.getThread.contact | phoneNumber }}
1010 </span >
1111 </v-toolbar-title >
1212 <v-spacer ></v-spacer >
2020 </v-tooltip >
2121 </v-app-bar >
2222 <v-container >
23- <div ref =" messageBody" class =" messages-body" >
23+ <div ref =" messageBody" class =" messages-body no-scrollbar " >
2424 <v-row v-for =" message in messages" :key =" message.id" >
2525 <v-col
2626 class =" d-flex"
4242 shaped
4343 :color =" isMT(message) ? 'primary' : 'default'"
4444 >
45- <v-card-text >{{ message.content }}</v-card-text >
45+ <v-card-text
46+ class =" text--primary"
47+ style =" white-space : pre-line "
48+ >{{ message.content }}</v-card-text
49+ >
4650 </v-card >
4751 <div class =" d-flex" >
48- <p class =" ml-2 text--secondary caption" >
52+ <p class =" ml-2 text--secondary caption mr-2 " >
4953 {{ new Date(message.order_timestamp).toLocaleString() }}
5054 </p >
5155 <v-spacer ></v-spacer >
5559 <v-progress-circular
5660 v-if =" isPending(message)"
5761 indeterminate
58- :size =" 16 "
62+ :size =" 14 "
5963 :width =" 1"
64+ class =" mt-n2"
6065 color =" primary"
6166 ></v-progress-circular >
6267 <v-icon
7782 </v-col >
7883 </v-row >
7984 </div >
80- <div class =" d-flex fixed-bottom" >
85+ <v-form
86+ ref =" form"
87+ class =" fixed-bottom d-flex"
88+ lazy-validation
89+ @submit.prevent =" sendMessage"
90+ >
8191 <v-textarea
92+ v-model =" formMessage"
93+ :disabled =" submitting"
8294 :rows =" 2"
83- placeholder =" Type your message here"
8495 filled
96+ class =" no-scrollbar"
97+ :rules =" formMessageRules"
98+ placeholder =" Type your message here"
8599 rounded
100+ @keydown.enter =" sendMessage"
86101 ></v-textarea >
87- <v-btn color =" primary" class =" pa-5 white--text ml-2 mt-1" fab >
102+ <v-btn
103+ :disabled =" submitting"
104+ type =" submit"
105+ color =" primary"
106+ class =" pa-5 white--text ml-2 mt-1"
107+ fab
108+ >
109+ <v-progress-circular
110+ v-if =" submitting"
111+ indeterminate
112+ style =" position : absolute "
113+ :size =" 20"
114+ :width =" 3"
115+ color =" pink"
116+ ></v-progress-circular >
88117 <v-icon >mdi-send</v-icon >
89118 </v-btn >
90- </div >
119+ </v-form >
91120 </v-container >
92121 </div >
93122</template >
94123
95124<script lang="ts">
96125import { Vue , Component } from ' vue-property-decorator'
126+ import { InputValidationRules } from ' vuetify'
97127import { Message } from ' ~/models/message'
128+ import { SendMessageRequest } from ' ~/store'
98129
99130@Component
100131export default class ThreadsIndex extends Vue {
132+ formMessage = ' '
133+ formMessageRules: InputValidationRules = [
134+ (v ) => !! v || ' Message is required' ,
135+ (v ) => (v && v .length <= 320 ) || ' Message must be less than 320 characters' ,
136+ ]
137+
138+ submitting = false
139+
101140 async mounted(): Promise <void > {
102141 await this .$store .dispatch (' loadThreads' )
103142 await this .$store .dispatch (' loadThreadMessages' , this .$route .params .id )
@@ -120,6 +159,31 @@ export default class ThreadsIndex extends Vue {
120159 const el: Element = this .$refs .messageBody as Element
121160 el .scrollTop = el .scrollHeight + 120
122161 }
162+
163+ async sendMessage(event : KeyboardEvent ) {
164+ if (event .shiftKey ) {
165+ return
166+ }
167+
168+ if (! (this .$refs .form as any ).validate ()) {
169+ return
170+ }
171+
172+ this .submitting = true
173+ const request: SendMessageRequest = {
174+ from: this .$store .getters .getOwner ,
175+ to: this .$store .getters .getThread .contact ,
176+ content: this .formMessage ,
177+ }
178+
179+ await this .$store .dispatch (' sendMessage' , request )
180+
181+ this .formMessage = ' '
182+ this .submitting = false
183+ ;(this .$refs .form as any ).reset ()
184+
185+ this .$nextTick (this .scrollToElement )
186+ }
123187}
124188 </script >
125189
@@ -136,11 +200,15 @@ export default class ThreadsIndex extends Vue {
136200 width : 96% ;
137201 max-height : calc (100vh - 200px );
138202 max-width : 1761px ;
203+ position : absolute ;
204+ bottom : 120px ;
205+ }
206+
207+ .no-scrollbar ,
208+ .no-scrollbar textarea {
139209 overflow-x : hidden ;
140210 -ms-overflow-style : none ; /* for Internet Explorer, Edge */
141211 overflow-y : scroll ;
142- position : absolute ;
143- bottom : 120px ;
144212 & ::-webkit-scrollbar {
145213 display : none ; /* for Chrome, Safari, and Opera */
146214 }
0 commit comments