Use new api/lottery/latest to check if todays lottery has already been archived. If yes we disable button and show dialog explaining how to reset to next weeks lottery.
		
			
				
	
	
		
			476 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			476 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="page-container">
 | |
|     <h1>Arkiver lotteri</h1>
 | |
| 
 | |
|     <h2>Registrer lodd kjøpt</h2>
 | |
| 
 | |
|     <div class="colors">
 | |
|       <div v-for="color in lotteryColors" :class="color.key + ' colors-box'" :key="color">
 | |
|         <div class="colors-overlay">
 | |
|           <p>{{ color.name }} kjøpt</p>
 | |
|           <input v-model.number="color.value" min="0" :placeholder="0" type="number" />
 | |
|         </div>
 | |
|       </div>
 | |
| 
 | |
|       <div class="label-div">
 | |
|         <label>Penger mottatt på vipps:</label>
 | |
|         <input v-model.number="payed" placeholder="NOK" type="number" :step="price || 1" min="0" />
 | |
|       </div>
 | |
|     </div>
 | |
| 
 | |
|     <div v-if="wines.length > 0">
 | |
|       <h2>Vinneres vin-valg</h2>
 | |
| 
 | |
|       <div class="winner-container">
 | |
|         <wine v-for="wine in wines" :key="wine.id" :wine="wine">
 | |
|           <div class="label-div">
 | |
|             <label for="potential-winner-name">Virtuelle vinnere</label>
 | |
|             <select id="potential-winner-name" type="text" placeholder="Navn" v-model="wine.winner">
 | |
|               <option v-for="winner in winners" :value="winner">{{ winner.name }}</option>
 | |
|             </select>
 | |
|           </div>
 | |
| 
 | |
|           <div class="winner-element">
 | |
|             <div class="color-selector">
 | |
|               <div class="label-div">
 | |
|                 <label>Farge vunnet</label>
 | |
|               </div>
 | |
| 
 | |
|               <button
 | |
|                 class="blue"
 | |
|                 :class="{ active: wine.winner.color == 'blue' }"
 | |
|                 @click="wine.winner.color = 'blue'"
 | |
|               ></button>
 | |
|               <button
 | |
|                 class="red"
 | |
|                 :class="{ active: wine.winner.color == 'red' }"
 | |
|                 @click="wine.winner.color = 'red'"
 | |
|               ></button>
 | |
|               <button
 | |
|                 class="green"
 | |
|                 :class="{ active: wine.winner.color == 'green' }"
 | |
|                 @click="wine.winner.color = 'green'"
 | |
|               ></button>
 | |
|               <button
 | |
|                 class="yellow"
 | |
|                 :class="{ active: wine.winner.color == 'yellow' }"
 | |
|                 @click="wine.winner.color = 'yellow'"
 | |
|               ></button>
 | |
|             </div>
 | |
|             <div class="label-div">
 | |
|               <label for="winner-name">Navn vinner</label>
 | |
|               <input id="winner-name" type="text" placeholder="Navn" v-model="wine.winner.name" />
 | |
|             </div>
 | |
|           </div>
 | |
|         </wine>
 | |
|       </div>
 | |
|     </div>
 | |
| 
 | |
|     <div v-if="wines.length > 0" class="button-container column">
 | |
|       <p v-if="todaysAlreadySubmitted" class="info-message">
 | |
|         Lotteriet er arkivert!<br />Du kan nå slette dagens viner, deltakere & vinnere for å tilbakestille til neste
 | |
|         ukes lotteri.
 | |
|       </p>
 | |
| 
 | |
|       <button class="vin-button" @click="archiveLottery" :disabled="todaysAlreadySubmitted">
 | |
|         {{ todaysAlreadySubmitted == false ? "Send inn og arkiver" : "Dagens lotteri er allerede arkivert" }}
 | |
|       </button>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import { dateString } from "@/utils";
 | |
| import Wine from "@/ui/Wine";
 | |
| 
 | |
| export default {
 | |
|   components: { Wine },
 | |
|   data() {
 | |
|     return {
 | |
|       payed: undefined,
 | |
|       todaysAlreadySubmitted: false,
 | |
|       wines: [],
 | |
|       winners: [],
 | |
|       attendees: [],
 | |
|       lotteryColors: [
 | |
|         { value: 0, name: "Blå", key: "blue" },
 | |
|         { value: 0, name: "Rød", key: "red" },
 | |
|         { value: 0, name: "Grønn", key: "green" },
 | |
|         { value: 0, name: "Gul", key: "yellow" }
 | |
|       ],
 | |
|       price: __PRICE__ || 10
 | |
|     };
 | |
|   },
 | |
|   created() {
 | |
|     this.fetchLotteryWines();
 | |
|     this.fetchLotteryWinners();
 | |
|     this.fetchLotteryAttendees();
 | |
|     this.checkIfAlreadySubmittedForToday();
 | |
|   },
 | |
|   watch: {
 | |
|     lotteryColors: {
 | |
|       deep: true,
 | |
|       handler() {
 | |
|         this.payed = this.getRaffleValue();
 | |
|       }
 | |
|     },
 | |
|     payed(val) {
 | |
|       this.$emit("counter", val);
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     wineWithWinnerMapper(wine) {
 | |
|       if (wine.winner == undefined) {
 | |
|         wine.winner = {
 | |
|           name: undefined,
 | |
|           color: undefined
 | |
|         };
 | |
|       }
 | |
|       return wine;
 | |
|     },
 | |
|     fetchLotteryWines() {
 | |
|       return fetch("/api/lottery/wines")
 | |
|         .then(resp => resp.json())
 | |
|         .then(response => {
 | |
|           if (response.success) {
 | |
|             this.wines = response.wines.map(this.wineWithWinnerMapper);
 | |
|           } else {
 | |
|             this.$toast.error({
 | |
|               title: "Klarte ikke hente viner.",
 | |
|               description: response.message
 | |
|             });
 | |
|           }
 | |
|         });
 | |
|     },
 | |
|     fetchLotteryWinners() {
 | |
|       return fetch("/api/lottery/winners")
 | |
|         .then(resp => resp.json())
 | |
|         .then(response => {
 | |
|           if (response.success) {
 | |
|             this.winners = response.winners;
 | |
|           } else {
 | |
|             this.$toast.error({
 | |
|               title: "Klarte ikke hente vinnere.",
 | |
|               description: response.message
 | |
|             });
 | |
|           }
 | |
|         });
 | |
|     },
 | |
|     fetchLotteryAttendees() {
 | |
|       return fetch("/api/lottery/attendees")
 | |
|         .then(resp => resp.json())
 | |
|         .then(response => {
 | |
|           if (response.success && response.attendees) {
 | |
|             this.attendees = response.attendees;
 | |
|             this.updateLotteryColorsWithAttendees(response.attendees)
 | |
|           } else {
 | |
|             this.$toast.error({
 | |
|               title: "Klarte ikke hente deltakere.",
 | |
|               description: response.message
 | |
|             });
 | |
|           }
 | |
|         });
 | |
|     },
 | |
|     checkIfAlreadySubmittedForToday() {
 | |
|       return fetch("/api/lottery/latest")
 | |
|         .then(resp => resp.json())
 | |
|         .then(response => {
 | |
|           const getDay = d => new Date(d).getDate();
 | |
| 
 | |
|           if (response.lottery.date && (getDay(response.lottery.date) == getDay(new Date()))) {
 | |
|             this.todaysAlreadySubmitted = true;
 | |
|           } else {
 | |
|             this.todaysAlreadySubmitted = false;
 | |
|           }
 | |
|         })
 | |
|     },
 | |
|     updateLotteryColorsWithAttendees(attendees) {
 | |
|       this.attendees.map(attendee => {
 | |
|         this.lotteryColors.map(color => (color.value += attendee[color.key]));
 | |
|       });
 | |
|     },
 | |
|     getRaffleValue() {
 | |
|       let rafflesBought = 0;
 | |
|       this.lotteryColors.map(color => rafflesBought += Number(color.value));
 | |
| 
 | |
|       return rafflesBought * this.price;
 | |
|     },
 | |
|     archiveLottery: async function(event) {
 | |
|       const validation = this.wines.every(wine => {
 | |
|         if (wine.winner.name == undefined || wine.winner.name == "") {
 | |
|           this.$toast.error({
 | |
|             title: `Navn på vinner må defineres for vin: ${wine.name}`
 | |
|           });
 | |
|           return false;
 | |
|         }
 | |
|         if (wine.winner.color == undefined || wine.winner.color == "") {
 | |
|           this.$toast.error({
 | |
|             title: `Farge vunnet må defineres for vin: ${wine.name}`
 | |
|           });
 | |
|           return false;
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|       });
 | |
| 
 | |
|       if (validation == false) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       let rafflesPayload = {};
 | |
|       this.lotteryColors.map(el => rafflesPayload.[el.key] = el.value);
 | |
| 
 | |
|       let stolen = 0;
 | |
|       const payedDiff = this.payed - this.getRaffleValue()
 | |
|       if (payedDiff) {
 | |
|         stolen = payedDiff / this.price;
 | |
|       }
 | |
| 
 | |
|       const payload = {
 | |
|         wines: this.wines,
 | |
|         raffles: rafflesPayload,
 | |
|         stolen: stolen
 | |
|       };
 | |
| 
 | |
|       const options = {
 | |
|         method: "POST",
 | |
|         headers: { "Content-Type": "application/json" },
 | |
|         body: JSON.stringify({
 | |
|           lottery: payload
 | |
|         })
 | |
|       };
 | |
| 
 | |
|       return fetch("/api/lottery/archive", options)
 | |
|         .then(resp => resp.json())
 | |
|         .then(response => {
 | |
|           if (response.success) {
 | |
|             this.todaysAlreadySubmitted = true;
 | |
|             this.$toast.info({
 | |
|               title: "Lotteriet er sendt inn og arkivert! Du kan nå slette viner, deltakere & vinnere slettes.",
 | |
|               timeout: 10000
 | |
|             });
 | |
|           } else {
 | |
|             this.$toast.error({
 | |
|               title: "Noe gikk galt under innsending!",
 | |
|               description: response.message
 | |
|             });
 | |
|           }
 | |
|         });
 | |
|     }
 | |
|   }
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| @import "@/styles/global.scss";
 | |
| @import "@/styles/media-queries.scss";
 | |
| 
 | |
| select {
 | |
|   margin: 0 0 auto;
 | |
|   height: 2rem;
 | |
|   min-width: 0;
 | |
|   width: 98%;
 | |
|   padding: 1%;
 | |
| }
 | |
| 
 | |
| .button-container {
 | |
|   margin-top: 1rem;
 | |
| }
 | |
| 
 | |
| .page-container {
 | |
|   padding: 0 1.5rem 3rem;
 | |
| 
 | |
|   @include desktop {
 | |
|     max-width: 60vw;
 | |
|     margin: 0 auto;
 | |
|   }
 | |
| }
 | |
| .winner-container {
 | |
|   width: 100%;
 | |
|   display: flex;
 | |
|   flex-wrap: wrap;
 | |
|   justify-content: space-around;
 | |
| 
 | |
|   > div {
 | |
|     margin: 1rem;
 | |
|     max-width: 350px;
 | |
|   }
 | |
| 
 | |
|   .button-container {
 | |
|     width: 100%;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .info-message {
 | |
|   padding: 0.75rem;
 | |
|   text-align: center;
 | |
|   background-color: var(--light-blue);
 | |
|   color: var(--matte-text-color);
 | |
|   border-radius: 4px;
 | |
| 
 | |
|   font-size: 1.1rem;
 | |
|   line-height: 1.5rem;
 | |
| }
 | |
| 
 | |
| .winner-element {
 | |
|   display: flex;
 | |
|   flex-direction: column;
 | |
| 
 | |
|   > div {
 | |
|     margin-bottom: 1rem;
 | |
|   }
 | |
| 
 | |
|   @include mobile {
 | |
|     width: 100%;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .color-selector {
 | |
|   margin-bottom: 0.65rem;
 | |
|   margin-right: 1rem;
 | |
| 
 | |
|   @include desktop {
 | |
|     min-width: 175px;
 | |
|   }
 | |
| 
 | |
|   @include mobile {
 | |
|     max-width: 25vw;
 | |
|   }
 | |
| 
 | |
|   .active {
 | |
|     border: 2px solid unset;
 | |
| 
 | |
|     &.green {
 | |
|       border-color: $green;
 | |
|     }
 | |
|     &.blue {
 | |
|       border-color: $dark-blue;
 | |
|     }
 | |
|     &.red {
 | |
|       border-color: $red;
 | |
|     }
 | |
|     &.yellow {
 | |
|       border-color: $dark-yellow;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   button {
 | |
|     border: 2px solid transparent;
 | |
|     display: inline-flex;
 | |
|     flex-wrap: wrap;
 | |
|     flex-direction: row;
 | |
|     height: 2.5rem;
 | |
|     width: 2.5rem;
 | |
| 
 | |
|     // disable-dbl-tap-zoom
 | |
|     touch-action: manipulation;
 | |
| 
 | |
|     @include mobile {
 | |
|       margin: 2px;
 | |
|     }
 | |
| 
 | |
|     &.green {
 | |
|       background: #c8f9df;
 | |
|     }
 | |
|     &.blue {
 | |
|       background: #d4f2fe;
 | |
|     }
 | |
|     &.red {
 | |
|       background: #fbd7de;
 | |
|     }
 | |
|     &.yellow {
 | |
|       background: #fff6d6;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| .colors {
 | |
|   display: flex;
 | |
|   flex-direction: row;
 | |
|   flex-wrap: wrap;
 | |
|   justify-content: center;
 | |
|   max-width: 1400px;
 | |
|   margin: 0 auto;
 | |
| 
 | |
|   @include mobile {
 | |
|     margin: 1.8rem auto 0;
 | |
|   }
 | |
| 
 | |
|   .label-div {
 | |
|     margin-top: 0.5rem;
 | |
|     width: 100%;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .colors-box {
 | |
|   width: 150px;
 | |
|   height: 150px;
 | |
|   margin: 20px;
 | |
|   -webkit-mask-image: url(/public/assets/images/lodd.svg);
 | |
|   background-repeat: no-repeat;
 | |
|   mask-image: url(/public/assets/images/lodd.svg);
 | |
|   -webkit-mask-repeat: no-repeat;
 | |
|   mask-repeat: no-repeat;
 | |
| 
 | |
|   @include mobile {
 | |
|     width: 120px;
 | |
|     height: 120px;
 | |
|     margin: 10px;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .colors-overlay {
 | |
|   display: flex;
 | |
|   justify-content: center;
 | |
|   height: 100%;
 | |
|   padding: 0 0.5rem;
 | |
|   position: relative;
 | |
| 
 | |
|   p {
 | |
|     margin: 0;
 | |
|     font-size: 0.8rem;
 | |
|     margin-bottom: 0.5rem;
 | |
|     text-transform: uppercase;
 | |
|     font-weight: 600;
 | |
|     position: absolute;
 | |
|     top: 0.4rem;
 | |
|     left: 0.5rem;
 | |
|   }
 | |
| 
 | |
|   input {
 | |
|     width: 70%;
 | |
|     border: 0;
 | |
|     padding: 0;
 | |
|     font-size: 3rem;
 | |
|     height: unset;
 | |
|     max-height: unset;
 | |
|     position: absolute;
 | |
|     bottom: 1.5rem;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .green,
 | |
| .green .colors-overlay > input {
 | |
|   background-color: $light-green;
 | |
|   color: $green;
 | |
| }
 | |
| 
 | |
| .blue,
 | |
| .blue .colors-overlay > input {
 | |
|   background-color: $light-blue;
 | |
|   color: $blue;
 | |
| }
 | |
| 
 | |
| .yellow,
 | |
| .yellow .colors-overlay > input {
 | |
|   background-color: $light-yellow;
 | |
|   color: $yellow;
 | |
| }
 | |
| 
 | |
| .red,
 | |
| .red .colors-overlay > input {
 | |
|   background-color: $light-red;
 | |
|   color: $red;
 | |
| }
 | |
| </style>
 |