From 05b07ca465a8407b49d11704605d37b0eff9567e Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Thu, 8 Oct 2020 23:39:38 +0200 Subject: [PATCH 01/59] Defined new route for PersonalHighscorePage. This is a subpage for showing additional information about a winner from highscore. --- src/router.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/router.js b/src/router.js index 757cf6a..78064b4 100644 --- a/src/router.js +++ b/src/router.js @@ -12,6 +12,7 @@ import WinnerPage from "@/components/WinnerPage"; import LotteryPage from "@/components/LotteryPage"; import HistoryPage from "@/components/HistoryPage"; import HighscorePage from "@/components/HighscorePage"; +import PersonalHighscorePage from "@/components/PersonalHighscorePage"; import RequestWine from "@/components/RequestWine"; import AllRequestedWines from "@/components/AllRequestedWines"; @@ -57,6 +58,10 @@ const routes = [ path: "/history", component: HistoryPage }, + { + path: "/highscore/:name", + component: PersonalHighscorePage + }, { path: "/highscore", component: HighscorePage From 9b2de7591077bab18f8c3ee9ecf88d69848dfae9 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Thu, 8 Oct 2020 23:41:18 +0200 Subject: [PATCH 02/59] Received and searched names are lowercased. Endpoint /lottery/by-name now lowercases the path input name and the search query towards mongo. --- api/lottery.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/lottery.js b/api/lottery.js index 17d8e29..7331990 100644 --- a/api/lottery.js +++ b/api/lottery.js @@ -98,8 +98,9 @@ const byEpochDate = (req, res) => { const byName = (req, res) => { const { name } = req.params; + const regexName = new RegExp(name, "i"); // lowercase regex of the name - return Highscore.find({ name }) + return Highscore.find({ "name": { $regex : regexName } }) .then(async (highscore) => { highscore = highscore[0] if (highscore) { From 0e8bf9546a68fc7fe036bcc62d44afd7377f7bde Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 9 Oct 2020 00:52:04 +0200 Subject: [PATCH 03/59] Reverse highscore for newest first. --- api/lottery.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api/lottery.js b/api/lottery.js index 7331990..244f0dd 100644 --- a/api/lottery.js +++ b/api/lottery.js @@ -82,11 +82,13 @@ const byEpochDate = (req, res) => { .then(highscore => getHighscoreByDates(highscore)) .then(async (lotteries) => { const lottery = lotteries[date]; + let highscoreWithResolvedWines = await resolveWineReferences(lottery) + highscoreWithResolvedWines = highscoreWithResolvedWines.reverse() if (lottery != null) { return res.send({ message: `Lottery for date: ${dateString}`, - lottery: await resolveWineReferences(lottery) + lottery: highscoreWithResolvedWines }) } else { return res.status(404).send({ @@ -104,7 +106,8 @@ const byName = (req, res) => { .then(async (highscore) => { highscore = highscore[0] if (highscore) { - const highscoreWithResolvedWines = await resolveWineReferences(highscore.wins) + let highscoreWithResolvedWines = await resolveWineReferences(highscore.wins) + highscoreWithResolvedWines = highscoreWithResolvedWines.reverse() return res.send({ message: `Lottery winnings by name: ${name}`, From 4c02c81cc3a32fbd7ffb5fde146f38511bd28759 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 9 Oct 2020 00:55:18 +0200 Subject: [PATCH 04/59] Name also part of highscore/by-name resp. --- api/lottery.js | 1 + 1 file changed, 1 insertion(+) diff --git a/api/lottery.js b/api/lottery.js index 244f0dd..aacd9df 100644 --- a/api/lottery.js +++ b/api/lottery.js @@ -111,6 +111,7 @@ const byName = (req, res) => { return res.send({ message: `Lottery winnings by name: ${name}`, + name: name, highscore: highscoreWithResolvedWines }) } else { From e87a59b1e64f9bb513f8c0bb724e060c3bd3ed1d Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 9 Oct 2020 00:55:47 +0200 Subject: [PATCH 05/59] Helper func for lottery/by-name. --- src/api.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/api.js b/src/api.js index 05145b9..2733701 100644 --- a/src/api.js +++ b/src/api.js @@ -333,6 +333,19 @@ const historyAll = () => { }); } +const getWinnerByName = (name) => { + const encodedName = encodeURIComponent(name) + const url = new URL(`/api/lottery/by-name/${name}`, BASE_URL); + + return fetch(url.href).then(resp => { + if (resp.ok) { + return resp.json(); + } else { + return handleErrors(resp); + } + }) +} + export { statistics, colorStatistics, @@ -364,5 +377,6 @@ export { finishedDraw, getAmIWinner, postWineChosen, - historyAll + historyAll, + getWinnerByName }; From 59792f9aae603c47ec94ace84ba1212969893ea9 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 9 Oct 2020 00:57:02 +0200 Subject: [PATCH 06/59] Moved date helper funcs to utils.js --- src/components/HighscorePage.vue | 11 +++-------- src/utils.js | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/components/HighscorePage.vue b/src/components/HighscorePage.vue index e082bd3..cf8e2c8 100644 --- a/src/components/HighscorePage.vue +++ b/src/components/HighscorePage.vue @@ -58,6 +58,7 @@ + + \ No newline at end of file From cb286b68942fc0691e0c7596f7fc0684f64edfab Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 9 Oct 2020 01:14:09 +0200 Subject: [PATCH 10/59] Back link and better wine name container width. --- src/components/PersonalHighscorePage.vue | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index a5992bb..530d326 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -4,7 +4,7 @@
- ⬅ + ⬅
@@ -96,16 +96,26 @@ export default { @import "./src/styles/variables"; @import "./src/styles/media-queries"; + $elementSpacing: 4rem; .el-spacing { margin-bottom: $elementSpacing; } +.go-back { + font-weight: normal; + font-size: 1.1rem; + border-width: 2px; + + &:not(:hover) { + border-color: $matte-text-color; + } +} .container { width: 90vw; margin: 0 auto; - max-width: 1500px; + max-width: 1200px; @include desktop { width: 80vw; @@ -180,7 +190,7 @@ h3 { display: inline-block; @include tablet { - width: calc(100% - 160px); + width: calc(100% - 160px - 80px); } & > * { @@ -194,7 +204,7 @@ h3 { } a { - font-size: 1.3rem; + font-size: 1.2rem; border-width: 2px; font-weight: normal; } From 4ce8ca1a99284a2d96b7035229720db39b08781a Mon Sep 17 00:00:00 2001 From: ingridvold Date: Fri, 9 Oct 2020 13:30:23 +0200 Subject: [PATCH 11/59] en morsom vri ;) --- src/components/HighscorePage.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/HighscorePage.vue b/src/components/HighscorePage.vue index e082bd3..574f45c 100644 --- a/src/components/HighscorePage.vue +++ b/src/components/HighscorePage.vue @@ -49,7 +49,7 @@
-

👈 Se dine vinn, trykk på navnet ditt

+

👈 Se dine vin(n), trykk på navnet ditt

From 98c2707cb0d16f6e887c3d666760db8dba7c96e6 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 12:06:44 +0200 Subject: [PATCH 12/59] Full rewrite, faster, better listing and less code. - Only list the highscore and send to PersonalHighscorePage on click. - List numbers are not sequential position in list, but the persons place in the highscore, allows shared place ranking. - Filter is a computed value that uses the filterInput, reduces overhead. - Stripped unused styling. --- src/components/HighscorePage.vue | 291 ++++++++++++------------------- 1 file changed, 107 insertions(+), 184 deletions(-) diff --git a/src/components/HighscorePage.vue b/src/components/HighscorePage.vue index cf8e2c8..afba5bc 100644 --- a/src/components/HighscorePage.vue +++ b/src/components/HighscorePage.vue @@ -1,56 +1,24 @@ @@ -65,10 +33,8 @@ export default { components: { Wine }, data() { return { - highscoreResponse: [], highscore: [], - highscoreFilter: '', - selectedWinner: null + filterInput: '' } }, async mounted() { @@ -79,171 +45,128 @@ export default { response = response.filter( person => person.name != null && person.name != "" ); - this.highscoreResponse = response - this.highscore = this.highscoreResponse; + this.highscore = this.generateScoreBoard(response); }, - watch: { - highscoreFilter(val) { + computed: { + filteredResults() { + let highscore = this.highscore; + let val = this.filterInput; + if (val.length) { - val = val.toLowerCase(); - this.highscore = this.highscoreResponse.filter(person => person.name.toLowerCase().includes(val)) - } else { - this.highscore = this.highscoreResponse + const nameIncludesString = (person) => person.name.toLowerCase().includes(val); + highscore = highscore.filter(nameIncludesString) } + + return highscore } }, methods: { - humanReadableDate: humanReadableDate, - daysAgo: daysAgo, + generateScoreBoard(highscore=this.highscore) { + let place = 0; + let highestWinCount = -1; + + return highscore.map(win => { + const wins = win.wins.length + if (wins != highestWinCount) { + place += 1 + highestWinCount = wins + } + + const placeString = place.toString().padStart(2, "0"); + win.rank = placeString; + return win + }) + }, resetFilter() { - this.highscore = this.highscoreResponse; - this.highscoreFilter = ''; + this.filterInput = ''; document.getElementsByTagName('input')[0].focus(); }, selectWinner(winner) { - if (this.selectedWinner != null && this.selectedWinner["name"] == winner["name"]) { - this.selectedWinner = null; - } else { - let newestFirst = winner.wins.sort((a, b) => a.date < b.date); - winner.wins = newestFirst; - this.selectedWinner = { ...winner }; - } + const path = "/highscore/" + encodeURIComponent(winner.name) + this.$router.push(path); }, - getRotation: function() { - let num = Math.floor(Math.random() * 12.5); - let neg = Math.floor(Math.random() * 2); - return neg == 0 ? -num : num; - } + humanReadableDate: humanReadableDate, + daysAgo: daysAgo } }; From 584d497c6af6f79adbd3fa6aab7b2c6cae656ad9 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 12:25:26 +0200 Subject: [PATCH 13/59] Click dates send to history page for given lottery. --- src/components/PersonalHighscorePage.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index 530d326..b6068cd 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -22,7 +22,9 @@

Flasker vunnet:

- {{ humanReadableDate(win.date) }} - {{ daysAgo(win.date) }} dager siden + + {{ humanReadableDate(win.date) }} - {{ daysAgo(win.date) }} dager siden +
@@ -81,6 +83,10 @@ export default { }) return colorOccurences }, + winDateUrl(date) { + const timestamp = new Date(date).getTime(); + return `/history/${timestamp}` + }, humanReadableDate: humanReadableDate, daysAgo: daysAgo }, From 1383a310b3e04cc7ba049b5e6d056860fc5d8b71 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 12:27:01 +0200 Subject: [PATCH 14/59] Try get a smaller version of the wine image. --- src/components/PersonalHighscorePage.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index b6068cd..1d7b397 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -27,7 +27,7 @@
- +

{{ win.wine.name }}

@@ -71,6 +71,11 @@ export default { this.winner = winner this.winningColors = this.findWinningColors() }, + smallerWineImage(image) { + if (image && image.includes(`515x515`)) + return image.replace(`515x515`, `175x175`) + return image + }, findWinningColors() { const colors = this.winner.highscore.map(win => win.color) const colorOccurences = {} From a59f1e2b1708e72474718484080388fff693ab13 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 12:29:07 +0200 Subject: [PATCH 15/59] Show error if no one w/ name found. --- src/components/PersonalHighscorePage.vue | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index 1d7b397..40fd738 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -40,6 +40,10 @@
+ +

+ {{ error }} +

@@ -58,7 +62,8 @@ export default { }, data() { return { - winner: undefined + winner: undefined, + error: undefined } }, computed: { @@ -66,6 +71,12 @@ export default { return this.winner.highscore.length } }, + created() { + const nameFromURL = this.$route.params.name; + getWinnerByName(nameFromURL) + .then(winner => this.setWinner(winner)) + .catch(err => this.error = `Ingen med navn: "${nameFromURL}" funnet.`) + }, methods: { setWinner(winner) { this.winner = winner @@ -94,11 +105,6 @@ export default { }, humanReadableDate: humanReadableDate, daysAgo: daysAgo - }, - created() { - const nameFromURL = this.$route.params.name; - if (this.winnerObject === undefined && nameFromURL !== null) - getWinnerByName(nameFromURL).then(winner => this.setWinner(winner)) } } From 8ef1a2dd88d12c73efb8cefc45e25913bc572765 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 13:32:44 +0200 Subject: [PATCH 16/59] Save previous route name, if none found push route highscore. --- src/components/PersonalHighscorePage.vue | 39 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index 40fd738..83c241c 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -3,9 +3,9 @@

Vinlottis highscore

- - ⬅ - + + ⬅ Tilbake til {{ previousRoute.name }} +

{{ winner.name }}

@@ -53,19 +53,23 @@ import { getWinnerByName } from "@/api"; import { humanReadableDate, daysAgo } from "@/utils"; export default { - props: { - winnerObject: { - type: Object, - required: false, - default: undefined - } - }, data() { return { winner: undefined, - error: undefined + error: undefined, + previousRoute: { + default: true, + name: "topplisten", + path: "/highscore" + } } }, + beforeRouteEnter(to, from, next) { + next(vm => { + if (from.name !== null) + vm.previousRoute = from + }) + }, computed: { numberOfWins() { return this.winner.highscore.length @@ -79,7 +83,11 @@ export default { }, methods: { setWinner(winner) { - this.winner = winner + this.winner = { + name: winner.name, + highscore: [], + ...winner + } this.winningColors = this.findWinningColors() }, smallerWineImage(image) { @@ -103,6 +111,13 @@ export default { const timestamp = new Date(date).getTime(); return `/history/${timestamp}` }, + navigateBack() { + if (this.previousRoute.default) { + this.$router.push({ path: this.previousRoute.path }); + } else { + this.$router.go(-1); + } + }, humanReadableDate: humanReadableDate, daysAgo: daysAgo } From 070250796398885c164f2072fa5757e06ec63494 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 13:36:16 +0200 Subject: [PATCH 17/59] Tabable back link. --- src/components/PersonalHighscorePage.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index 83c241c..a6837e9 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -3,7 +3,7 @@

Vinlottis highscore

- + Tilbake til {{ previousRoute.name }} From 27f4c8faef5358cbac7244137fedab91791a5923 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 13:36:32 +0200 Subject: [PATCH 18/59] Updated styling to match design. --- src/components/PersonalHighscorePage.vue | 72 +++++++++++++----------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index a6837e9..69610cd 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -29,7 +29,7 @@
-
+

{{ win.wine.name }}

Les mer på vinmonopolet.no @@ -128,25 +128,24 @@ export default { @import "./src/styles/variables"; @import "./src/styles/media-queries"; - -$elementSpacing: 4rem; +$elementSpacing: 3rem; .el-spacing { margin-bottom: $elementSpacing; } -.go-back { +.navigate-back { font-weight: normal; - font-size: 1.1rem; + font-size: 1.2rem; border-width: 2px; - - &:not(:hover) { - border-color: $matte-text-color; - } + border-color: gray; } + .container { width: 90vw; - margin: 0 auto; + margin: 3rem auto; + margin-bottom: 0; + padding-bottom: 3rem; max-width: 1200px; @include desktop { @@ -155,24 +154,27 @@ $elementSpacing: 4rem; } h1 { - font-size: 2.8rem; + font-size: 3rem; font-family: "knowit"; font-weight: normal; } -h3 { - display: inline-block; -} - .name { text-transform: capitalize; - font-size: 2.2rem; + font-size: 3.5rem; font-family: "knowit"; font-weight: normal; + margin: 2rem 0 1rem 0; +} + +.error { + font-size: 2.5rem; + font-weight: normal; } .win-count { - font-size: 1.2rem; + font-size: 1.5rem; + margin-top: 0; } .raffle-container { @@ -180,18 +182,17 @@ h3 { margin-top: 1rem; div:not(:last-of-type) { - margin-right: 1rem; + margin-right: 1.5rem; } } .raffle-element { - width: 80px; - height: 60px; + width: 5rem; + height: 4rem; display: flex; justify-content: center; align-items: center; - font-size: 1.2rem; + font-size: 1.5rem; margin-top: 0; - margin-bottom: 0; &.small { height: 40px; @@ -199,10 +200,19 @@ h3 { } } +.days-ago { + color: $matte-text-color; + border-bottom: 2px solid transparent; + + &:hover { + border-color: $link-color; + } +} + .won-wine { --spacing: 1rem; background-color: white; - margin: var(--spacing) 0 4rem 0; + margin: var(--spacing) 0 3rem 0; padding: var(--spacing); position: relative; @@ -212,12 +222,11 @@ h3 { } img { - // width: 60px; margin: 0 3rem; height: 160px; } - .wine-details { + &-details { vertical-align: top; display: inline-block; @@ -244,8 +253,8 @@ h3 { .raffle-element { position: absolute; - top: var(--spacing); - right: var(--spacing); + top: calc(var(--spacing) * 2); + right: calc(var(--spacing) * 2); margin: 0; } } @@ -254,14 +263,11 @@ h3 { .backdrop { $background: rgb(244,244,244); - --horizontal-padding: 2rem; + --padding: 2rem; @include desktop { - $horizontal-padding: 5rem; + --padding: 5rem; } background-color: $background; - height: 100%; - width: calc(100% - calc(var(--horizontal-padding) * 2); - - padding: 2rem var(--horizontal-padding); + padding: var(--padding); } \ No newline at end of file From 9d9947d7dc0b9c61e08661583b52b7f5bc57d54e Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 13:53:08 +0200 Subject: [PATCH 19/59] Router mode history, and all routes got names. --- src/router.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/router.js b/src/router.js index 757cf6a..2dad198 100644 --- a/src/router.js +++ b/src/router.js @@ -1,3 +1,5 @@ +import VueRouter from "vue-router"; + import VinlottisPage from "@/components/VinlottisPage"; import GeneratePage from "@/components/GeneratePage"; import TodaysPage from "@/components/TodaysPage"; @@ -19,30 +21,37 @@ import AllRequestedWines from "@/components/AllRequestedWines"; const routes = [ { path: "*", + name: "Hjem", component: VinlottisPage }, { path: "/lottery", + name: "Lotteri", component: LotteryPage }, { path: "/dagens", + name: "Dagens vin", component: TodaysPage }, { path: "/viner", + name: "Alle viner", component: AllWinesPage }, { path: "/login", + name: "Login", component: LoginPage }, { path: "/create", + name: "Registrer", component: CreatePage }, { path: "/admin", + name: "Admin", component: AdminPage }, { @@ -54,21 +63,40 @@ const routes = [ component: WinnerPage }, { - path: "/history", + path: "/history/:date", + name: "Historie for dato", component: HistoryPage }, + { + path: "/history/", + name: "Historie", + component: HistoryPage + }, + { + path: "/highscore/:name", + name: "Personlig toppliste", + component: PersonalHighscorePage + }, { path: "/highscore", + name: "Topplisten", component: HighscorePage }, { path: "/request", + name: "Etterspør vin", component: RequestWine }, { path: "/requested-wines", + name: "Etterspurte viner", component: AllRequestedWines } ]; -export { routes }; +const router = new VueRouter({ + routes: routes, + mode: "history" +}); + +export default router; From 2062f64999f06c9d70e39f88fe69aabaac58412c Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 13:54:16 +0200 Subject: [PATCH 20/59] Import VueRouter instance from router.js. --- src/vinlottis-init.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/vinlottis-init.js b/src/vinlottis-init.js index f362976..52cc5a7 100644 --- a/src/vinlottis-init.js +++ b/src/vinlottis-init.js @@ -1,6 +1,6 @@ import Vue from "vue"; import VueRouter from "vue-router"; -import { routes } from "@/router.js"; +import VinlottisRouter from "@/router.js"; import Vinlottis from "@/Vinlottis"; import VueAnalytics from "vue-analytics"; @@ -9,13 +9,9 @@ Vue.use(VueAnalytics, { id: "UA-156846886-1" }); -const router = new VueRouter({ - routes: routes -}); - new Vue({ el: "#app", - router, + router: VinlottisRouter, components: { Vinlottis }, template: "", render: h => h(Vinlottis) From 092396554412693fbf665fcc6462cdb7c2e21316 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 13:56:17 +0200 Subject: [PATCH 21/59] Removed hash from routes. --- api/message.js | 2 +- api/update.js | 2 +- src/components/VinlottisPage.vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/message.js b/api/message.js index a763a7b..d385019 100644 --- a/api/message.js +++ b/api/message.js @@ -7,7 +7,7 @@ async function sendWineSelectMessage(winnerObject) { winnerObject.timestamp_limit = new Date().getTime() * 600000; await winnerObject.save(); - let url = new URL(`/#/winner/${winnerObject.id}`, "https://lottis.vin"); + let url = new URL(`/winner/${winnerObject.id}`, "https://lottis.vin"); return sendMessageToUser( winnerObject.phoneNumber, diff --git a/api/update.js b/api/update.js index 59642dc..785ae0c 100644 --- a/api/update.js +++ b/api/update.js @@ -39,7 +39,7 @@ const submitWines = async (req, res) => { const message = JSON.stringify({ message: "Dagens vin er lagt til, se den på lottis.vin/dagens!", title: "Ny vin!", - link: "/#/dagens" + link: "/dagens" }); try { diff --git a/src/components/VinlottisPage.vue b/src/components/VinlottisPage.vue index e683a12..a7b1afd 100644 --- a/src/components/VinlottisPage.vue +++ b/src/components/VinlottisPage.vue @@ -13,7 +13,7 @@ />
- Vil du til lotteriet?Trykk her + Vil du til lotteriet?Trykk her
From 0e74534cde4539ae0c007f241f20af5ab2ee9797 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 14:00:42 +0200 Subject: [PATCH 22/59] Removed unnecessary mongo connection string. --- api/lottery.js | 5 ----- api/retrieve.js | 4 ---- api/subscriptions.js | 5 ----- api/update.js | 4 ---- 4 files changed, 18 deletions(-) diff --git a/api/lottery.js b/api/lottery.js index 17d8e29..2a0145f 100644 --- a/api/lottery.js +++ b/api/lottery.js @@ -1,10 +1,5 @@ const path = require('path'); -const mongoose = require('mongoose'); -mongoose.connect('mongodb://localhost:27017/vinlottis', { - useNewUrlParser: true -}) - const Highscore = require(path.join(__dirname + '/../schemas/Highscore')); const Wine = require(path.join(__dirname + '/../schemas/Wine')); diff --git a/api/retrieve.js b/api/retrieve.js index 92bb2a6..d377c60 100644 --- a/api/retrieve.js +++ b/api/retrieve.js @@ -1,8 +1,4 @@ const path = require("path"); -const mongoose = require("mongoose"); -mongoose.connect("mongodb://localhost:27017/vinlottis", { - useNewUrlParser: true -}); const Purchase = require(path.join(__dirname + "/../schemas/Purchase")); const Wine = require(path.join(__dirname + "/../schemas/Wine")); diff --git a/api/subscriptions.js b/api/subscriptions.js index 574280c..1d61a08 100644 --- a/api/subscriptions.js +++ b/api/subscriptions.js @@ -2,13 +2,8 @@ const express = require("express"); const path = require("path"); const router = express.Router(); const webpush = require("web-push"); //requiring the web-push module -const mongoose = require("mongoose"); const schedule = require("node-schedule"); -mongoose.connect("mongodb://localhost:27017/vinlottis", { - useNewUrlParser: true -}); - const mustBeAuthenticated = require(path.join( __dirname + "/../middleware/mustBeAuthenticated" )); diff --git a/api/update.js b/api/update.js index 59642dc..c3fa4d1 100644 --- a/api/update.js +++ b/api/update.js @@ -1,9 +1,5 @@ const express = require("express"); const path = require("path"); -const mongoose = require("mongoose"); -mongoose.connect("mongodb://localhost:27017/vinlottis", { - useNewUrlParser: true -}); const sub = require(path.join(__dirname + "/../api/subscriptions")); From 90eb557f0b14f7477c050011a92223d3b6a6aaf0 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 14:04:08 +0200 Subject: [PATCH 23/59] New api route for history by date. --- src/api.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/api.js b/src/api.js index 05145b9..e747b1f 100644 --- a/src/api.js +++ b/src/api.js @@ -333,6 +333,18 @@ const historyAll = () => { }); } +const historyByDate = (date) => { + const url = new URL(`/api/lottery/by-date/${ date }`, BASE_URL); + + return fetch(url.href).then(resp => { + if (resp.ok) { + return resp.json(); + } else { + return handleErrors(resp); + } + }); +} + export { statistics, colorStatistics, @@ -364,5 +376,6 @@ export { finishedDraw, getAmIWinner, postWineChosen, - historyAll + historyAll, + historyByDate }; From 20be3cc5cac7cbeea591693886509113a22ca3f7 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 14:04:42 +0200 Subject: [PATCH 24/59] If date in params, fetch only that date. - Now handles only fetching date by epoch from url params. - Displays date w/ helper function humanReadableDate. --- src/components/HistoryPage.vue | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/HistoryPage.vue b/src/components/HistoryPage.vue index 372e348..c1951b4 100644 --- a/src/components/HistoryPage.vue +++ b/src/components/HistoryPage.vue @@ -2,14 +2,15 @@

Historie fra tidligere lotteri

-
- +
+
From c0f26f9061005f3c82ffa4b226a4f0190352952d Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 15:26:11 +0200 Subject: [PATCH 25/59] Refactored lottery controller. --- api/lottery.js | 123 +++++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/api/lottery.js b/api/lottery.js index 2a0145f..3ed217a 100644 --- a/api/lottery.js +++ b/api/lottery.js @@ -6,53 +6,61 @@ const Wine = require(path.join(__dirname + '/../schemas/Wine')); // Utils const epochToDateString = date => new Date(parseInt(date)).toDateString(); -const getHighscoreByDates = highscore => { - let groupedLotteries = {} +const sortNewestFirst = (lotteries) => { + return lotteries.sort((a, b) => parseInt(a.date) < parseInt(b.date) ? 1 : -1) +} - highscore.forEach(user => { - user.wins.map(win => { +const groupHighscoreByDate = async (highscore=undefined) => { + if (highscore == undefined) + highscore = await Highscore.find(); + + const highscoreByDate = []; + + highscore.forEach(person => { + person.wins.map(win => { const epochDate = new Date(win.date).setHours(0,0,0,0); - const obj = { - name: user.name, + const winnerObject = { + name: person.name, color: win.color, wine: win.wine, date: epochDate } - groupedLotteries[epochDate] ? - groupedLotteries[epochDate].push(obj) : groupedLotteries[epochDate] = [obj]; + const existingDateIndex = highscoreByDate.findIndex(el => el.date == epochDate) + if (existingDateIndex > -1) + highscoreByDate[existingDateIndex].winners.push(winnerObject); + else + highscoreByDate.push({ + date: epochDate, + winners: [winnerObject] + }) }) }) - return groupedLotteries + return sortNewestFirst(highscoreByDate); } -const groupedHighscoreToSortedList = groupedLotteries => { - return Object.keys(groupedLotteries).map(key => { - const winners = groupedLotteries[key]; - return { - date: parseInt(key), - dateString: epochToDateString(key), - winners - } - }).sort((a,b) => parseInt(a.date) > parseInt(b.date) ? 1 : -1) -} +const resolveWineReferences = (highscoreObject, key) => { + const listWithWines = highscoreObject[key] -const resolveWineReferences = listWithWines => { return Promise.all(listWithWines.map(element => - Wine.findById(element.wine) - .then(wine => { - element.wine = wine - return element - }) - )) + Wine.findById(element.wine) + .then(wine => { + element.wine = wine + return element + })) + ) + .then(resolvedListWithWines => { + highscoreObject[key] = resolvedListWithWines; + return highscoreObject + }) } +// end utils // Routes const all = (req, res) => { return Highscore.find() - .then(highscore => getHighscoreByDates(highscore)) - .then(groupedLotteries => groupedHighscoreToSortedList(groupedLotteries)) + .then(highscore => groupHighscoreByDate(highscore)) .then(lotteries => res.send({ message: "Lotteries by date!", lotteries @@ -60,56 +68,59 @@ const all = (req, res) => { } const latest = (req, res) => { - return Highscore.find() - .then(highscore => getHighscoreByDates(highscore)) - .then(groupedLotteries => groupedHighscoreToSortedList(groupedLotteries)) - .then(lotteries => res.send({ - message: "Latest lottery!", - lottery: lotteries.slice(-1).pop() - })) + return groupHighscoreByDate() + .then(lotteries => lotteries.shift()) + .then(latestLottery => resolveWineReferences(latestLottery, "winners")) + .then(lottery => res.send({ + message: "Latest lottery!", + winners: lottery.winners + }) + ) } const byEpochDate = (req, res) => { - const { date } = req.params; + let { date } = req.params; + date = new Date(new Date(parseInt(date)).setHours(0,0,0,0)).getTime() const dateString = epochToDateString(date); - return Highscore.find() - .then(highscore => getHighscoreByDates(highscore)) - .then(async (lotteries) => { - const lottery = lotteries[date]; - - if (lottery != null) { - return res.send({ - message: `Lottery for date: ${dateString}`, - lottery: await resolveWineReferences(lottery) - }) + return groupHighscoreByDate() + .then(lotteries => { + const lottery = lotteries.filter(lottery => lottery.date == date) + if (lottery.length > 0) { + return lottery[0] } else { return res.status(404).send({ - message: `No lottery found for date: ${dateString}` + message: `No lottery found for date: ${ dateString }` }) } }) + .then(lottery => resolveWineReferences(lottery, "winners")) + .then(lottery => res.send({ + message: `Lottery for date: ${ dateString}`, + date, + winners: lottery.winners + })) } const byName = (req, res) => { const { name } = req.params; return Highscore.find({ name }) - .then(async (highscore) => { - highscore = highscore[0] - if (highscore) { - const highscoreWithResolvedWines = await resolveWineReferences(highscore.wins) - - return res.send({ - message: `Lottery winnings by name: ${name}`, - highscore: highscoreWithResolvedWines - }) + .then(highscore => { + if (highscore.length > 0) { + return highscore[0] } else { return res.status(404).send({ message: `Name: ${ name } not found in leaderboards.` }) } }) + .then(highscore => resolveWineReferences(highscore, "wins")) + .then(highscore => res.send({ + message: `Lottery winnings for name: ${ name }.`, + name: highscore.name, + wins: highscore.wins + })) } module.exports = { From 03c13d9558a19eb65f5547d711db23f7d77eaade Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 15:27:00 +0200 Subject: [PATCH 26/59] Linting. --- src/components/HistoryPage.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/HistoryPage.vue b/src/components/HistoryPage.vue index c1951b4..2e60cf2 100644 --- a/src/components/HistoryPage.vue +++ b/src/components/HistoryPage.vue @@ -3,7 +3,7 @@

Historie fra tidligere lotteri

- +
From 823bbb743769d07fb04ae3c43b8216b6a94d8ba6 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 15:42:45 +0200 Subject: [PATCH 27/59] Winners clickable to route to highscore/{name}. --- src/ui/Winners.vue | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/Winners.vue b/src/ui/Winners.vue index fc76fd6..9258039 100644 --- a/src/ui/Winners.vue +++ b/src/ui/Winners.vue @@ -2,8 +2,10 @@

{{ title ? title : 'Vinnere' }}

-
-
{{ winner.name }}
+
+ +
{{ winner.name }}
+
From 52dedd1e7c3d9ab62d98bbc4bb67f0cb7568087a Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 15:39:11 +0200 Subject: [PATCH 28/59] Renamed all references to ballot to raffle. --- api/virtualLottery.js | 16 +++++----- src/components/GeneratePage.vue | 6 ++-- .../VirtualLotteryRegistrationPage.vue | 30 +++++++++---------- src/styles/global.scss | 10 +++---- src/ui/Attendees.vue | 10 +++---- src/ui/TotalBought.vue | 8 ++--- src/ui/WinnerDraw.vue | 10 +++---- src/ui/Winners.vue | 4 +-- 8 files changed, 47 insertions(+), 47 deletions(-) diff --git a/api/virtualLottery.js b/api/virtualLottery.js index 81107dc..e9ec85f 100644 --- a/api/virtualLottery.js +++ b/api/virtualLottery.js @@ -45,7 +45,7 @@ const attendees = async (req, res) => { attendee = attendees[i]; attendeesRedacted.push({ name: attendee.name, - ballots: attendee.red + attendee.blue + attendee.yellow + attendee.green, + raffles: attendee.red + attendee.blue + attendee.yellow + attendee.green, red: attendee.red, blue: attendee.blue, green: attendee.green, @@ -99,27 +99,27 @@ const drawWinner = async (req, res) => { message: "No attendees left that have not won." }); } - let ballotColors = []; + let raffleColors = []; for (let i = 0; i < allContestants.length; i++) { let currentContestant = allContestants[i]; for (let blue = 0; blue < currentContestant.blue; blue++) { - ballotColors.push("blue"); + raffleColors.push("blue"); } for (let red = 0; red < currentContestant.red; red++) { - ballotColors.push("red"); + raffleColors.push("red"); } for (let green = 0; green < currentContestant.green; green++) { - ballotColors.push("green"); + raffleColors.push("green"); } for (let yellow = 0; yellow < currentContestant.yellow; yellow++) { - ballotColors.push("yellow"); + raffleColors.push("yellow"); } } - ballotColors = shuffle(ballotColors); + raffleColors = shuffle(raffleColors); let colorToChooseFrom = - ballotColors[Math.floor(Math.random() * ballotColors.length)]; + raffleColors[Math.floor(Math.random() * raffleColors.length)]; let findObject = { winner: false }; findObject[colorToChooseFrom] = { $gt: 0 }; diff --git a/src/components/GeneratePage.vue b/src/components/GeneratePage.vue index a77e780..e149888 100644 --- a/src/components/GeneratePage.vue +++ b/src/components/GeneratePage.vue @@ -5,9 +5,9 @@ Velg hvilke farger du vil ha, fyll inn antall lodd og klikk 'generer'

- + - +
@@ -27,7 +27,7 @@ export default { data() { return { hardStart: false, - numberOfBallots: null + numberOfRaffles: null }; }, mounted() { diff --git a/src/components/VirtualLotteryRegistrationPage.vue b/src/components/VirtualLotteryRegistrationPage.vue index cff8fe8..153c6e9 100644 --- a/src/components/VirtualLotteryRegistrationPage.vue +++ b/src/components/VirtualLotteryRegistrationPage.vue @@ -18,7 +18,7 @@

Vinnere

-
+
{{ winner.name }} {{ winner.phoneNumber }} Rød: {{ winner.red }} @@ -47,11 +47,11 @@ {{ attendee.name }} {{ attendee.phoneNumber }}
-
-
{{ attendee.red }}
-
{{ attendee.blue }}
-
{{ attendee.green }}
-
{{ attendee.yellow }}
+
+
{{ attendee.red }}
+
{{ attendee.blue }}
+
{{ attendee.green }}
+
{{ attendee.yellow }}
@@ -140,7 +140,7 @@ export default { blue: 0, green: 0, yellow: 0, - ballots: 0, + raffles: 0, randomColors: false, attendees: [], winners: [], @@ -197,7 +197,7 @@ export default { blue: this.blue, green: this.green, yellow: this.yellow, - ballots: this.ballots + raffles: this.raffles }); if (response == true) { @@ -354,7 +354,7 @@ hr { } } -.ballot-element { +.raffle-element { width: 140px; height: 150px; margin: 20px 0; @@ -378,19 +378,19 @@ hr { font-size: 1rem; } - &.green-ballot { + &.green-raffle { background-color: $light-green; } - &.blue-ballot { + &.blue-raffle { background-color: $light-blue; } - &.yellow-ballot { + &.yellow-raffle { background-color: $light-yellow; } - &.red-ballot { + &.red-raffle { background-color: $light-red; } } @@ -422,7 +422,7 @@ button { margin: 0 auto; & .name-and-phone, - & .ballots-container { + & .raffles-container { display: flex; justify-content: center; } @@ -431,7 +431,7 @@ button { flex-direction: column; } - & .ballots-container { + & .raffles-container { flex-direction: row; } } diff --git a/src/styles/global.scss b/src/styles/global.scss index d4bbfce..5a76392 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -199,7 +199,7 @@ textarea { margin: 0 !important; } -.ballot-element { +.raffle-element { margin: 20px 0; -webkit-mask-image: url(/../../public/assets/images/lodd.svg); background-repeat: no-repeat; @@ -208,19 +208,19 @@ textarea { mask-repeat: no-repeat; color: #333333; - &.green-ballot { + &.green-raffle { background-color: $light-green; } - &.blue-ballot { + &.blue-raffle { background-color: $light-blue; } - &.yellow-ballot { + &.yellow-raffle { background-color: $light-yellow; } - &.red-ballot { + &.red-raffle { background-color: $light-red; } } diff --git a/src/ui/Attendees.vue b/src/ui/Attendees.vue index 6b6b819..92f4a64 100644 --- a/src/ui/Attendees.vue +++ b/src/ui/Attendees.vue @@ -4,10 +4,10 @@
{{ attendee.name }} -
{{ attendee.red }}
-
{{ attendee.blue }}
-
{{ attendee.green }}
-
{{ attendee.yellow }}
+
{{ attendee.red }}
+
{{ attendee.blue }}
+
{{ attendee.green }}
+
{{ attendee.yellow }}
@@ -46,7 +46,7 @@ export default { width: 60%; } -.ballot-element { +.raffle-element { font-size: 0.75rem; width: 45px; height: 45px; diff --git a/src/ui/TotalBought.vue b/src/ui/TotalBought.vue index 217cd84..4d1f936 100644 --- a/src/ui/TotalBought.vue +++ b/src/ui/TotalBought.vue @@ -8,7 +8,7 @@ color.name + '-container ' + color.name + - '-ballot inner-bought-container ballot-element' + '-raffle inner-bought-container raffle-element' " :key="color.name" > @@ -24,7 +24,7 @@
-
+
Totalt 
@@ -136,7 +136,7 @@ export default { align-items: center; } -.ballot-element { +.raffle-element { width: 140px; height: 150px; margin: 20px 0; @@ -166,7 +166,7 @@ export default { } } -.total-ballots { +.total-raffles { width: 150px; height: 150px; margin: 20px 0; diff --git a/src/ui/WinnerDraw.vue b/src/ui/WinnerDraw.vue index 1cd3d8d..81c04ec 100644 --- a/src/ui/WinnerDraw.vue +++ b/src/ui/WinnerDraw.vue @@ -3,8 +3,8 @@

TREKKER

{{ currentName }} @@ -19,8 +19,8 @@

VINNER

{{ currentName }} @@ -204,7 +204,7 @@ h2 { align-items: center; } -.ballot-element { +.raffle-element { width: 140px; height: 140px; font-size: 1.2rem; diff --git a/src/ui/Winners.vue b/src/ui/Winners.vue index fc76fd6..238c955 100644 --- a/src/ui/Winners.vue +++ b/src/ui/Winners.vue @@ -3,7 +3,7 @@

{{ title ? title : 'Vinnere' }}

-
{{ winner.name }}
+
{{ winner.name }}
@@ -40,7 +40,7 @@ h2 { flex-wrap: wrap; } -.ballot-element { +.raffle-element { font-size: 1rem; width: 145px; height: 145px; From 5f973b199d81eb3b419ef1f2c1800531b3e311fe Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 15:55:15 +0200 Subject: [PATCH 29/59] All wines endpoint returns newest first. --- api/retrieve.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/retrieve.js b/api/retrieve.js index d377c60..a90b95f 100644 --- a/api/retrieve.js +++ b/api/retrieve.js @@ -139,7 +139,9 @@ const allWinesSummary = async (req, res) => { } } - return res.json(Object.values(wines)); + wines = Object.values(wines).reverse() + + return res.json(wines); }; module.exports = { From 64a1a8a93a89c29e98cf226e368e82e867cc40ee Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 16:24:44 +0200 Subject: [PATCH 30/59] Updated wine w/ new design, removed lots of code. Updated wine component to reflect changes in design. Removed all methods, computed and unnecessary props. The inlineSlot props has been removed, now slot always renders inline. Removed functions for custom logic, not this is resides in the parent and should be passed down in the slot. --- src/ui/Wine.vue | 211 ++++++++++++++++-------------------------------- 1 file changed, 68 insertions(+), 143 deletions(-) diff --git a/src/ui/Wine.vue b/src/ui/Wine.vue index 8dd0a5e..9c31a1b 100644 --- a/src/ui/Wine.vue +++ b/src/ui/Wine.vue @@ -1,39 +1,27 @@ @@ -43,36 +31,6 @@ export default { wine: { type: Object, required: true - }, - fullscreen: { - type: Boolean, - required: false - }, - inlineSlot: { - type: Boolean, - required: false, - default: false - }, - winner: { - type: Boolean, - required: false, - default: false - } - }, - methods: { - shouldUseInlineSlot() { - return this.inlineSlot && window.innerWidth > 768; - }, - hostname(url) { - const urlHostname = new URL(url).hostname; - return urlHostname.split(".")[ - (urlHostname.match(/\./g) || []).length - 1 - ]; - }, - choseWine(name) { - if (window.confirm(`Er du sikker på at du vil ha ${name}?`)) { - this.$emit("chosen", name); - } } } }; @@ -83,100 +41,67 @@ export default { @import "./src/styles/global"; @import "./src/styles/variables"; -.wine-image { - height: 250px; +.wine { + padding: 2rem; + margin: 1rem 0rem; + position: relative; + -webkit-box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.15); - @include mobile { - max-width: 90px; - object-fit: cover; - } - - &.fullscreen { - @include desktop { - height: 100%; - max-height: 65vh; - max-width: 275px; - object-fit: cover; - } + @include tablet { + width: 250px; + height: 100%; + margin: 1rem 2rem; } } -.wine-placeholder { - height: 250px; - width: 70px; + +.wine-image { + display: flex; + justify-content: center; + + img { + height: 250px; + @include mobile { + object-fit: cover; + max-width: 90px; + } + } + .wine-placeholder { + height: 250px; + width: 70px; + } +} + +.wine-details { + display: flex; + flex-direction: column; } h2 { + font-weight: normal; + font-size: 1.4rem; + margin: 2rem 0; + color: $matte-text-color; +} + +.bottom-section { width: 100%; - max-width: 30vw; - - @include mobile { - max-width: 50vw; - } -} - -.wine-container { - margin-bottom: 30px; - font-family: Arial; - width: 100%; - max-width: max-content; - - &.big { - align-items: center; - } - - @include desktop { - max-width: 550px; - } -} - -.left { - float: left; - margin-right: 3rem; - - @include mobile { - margin-right: 2rem; - } -} - -.right { - margin-bottom: 2rem; - display: flex; - flex-direction: column; - height: max-content; - - > div:first-of-type { - display: flex; - flex-direction: column; - } -} - -a, -a:focus, -a:hover, -a:visited { - color: #333333; - font-family: Arial; - text-decoration: none; - font-weight: bold; -} - -.wine-link { - color: #333333; - font-family: Arial; - text-decoration: none; - font-weight: bold; - border-bottom: 1px solid $link-color; - width: fit-content; -} - -.button-container { - & button.red { - background-color: $light-red; - color: $red; - } -} - -.vin-button { margin-top: 1rem; + background-color: NavajoWhite; + + .link { + color: $matte-text-color; + font-family: Arial; + font-size: 1.2rem; + cursor: pointer; + font-weight: normal; + border-bottom: 2px solid $matte-text-color; + + &:hover { + font-weight: normal; + border-color: $link-color; + } + } } \ No newline at end of file From 5f2b29324dfd8dde1cd1a3993219e9bbe1a77177 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 16:31:40 +0200 Subject: [PATCH 31/59] Reflecting changes no longer use props in Wine.vue Reflecting changes now that wine should not have custom logic. No longer send prop values other than wine down. WinnerPage function called from the slot passed down, not using custom :winner prop and @chosenWine event. --- src/components/RegisterPage.vue | 12 ++++++++---- src/components/TodaysPage.vue | 12 +++++------- src/components/WinnerPage.vue | 34 ++++++++++++++++----------------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/components/RegisterPage.vue b/src/components/RegisterPage.vue index 0cebbe9..52345d4 100644 --- a/src/components/RegisterPage.vue +++ b/src/components/RegisterPage.vue @@ -85,7 +85,7 @@

Vinnere

Refresh data fra virtuelt lotteri
- +
@@ -500,6 +500,10 @@ hr { color: grey; } +.button-container { + margin-top: 1rem; +} + .page-container { padding: 0 1.5rem 3rem; @@ -537,10 +541,10 @@ hr { } .winner-element { display: flex; - flex-direction: row; + flex-direction: column; - @include desktop { - margin-top: 1.5rem; + > div { + margin-bottom: 1rem; } @include mobile { diff --git a/src/components/TodaysPage.vue b/src/components/TodaysPage.vue index 0dfdf12..0ec99f3 100644 --- a/src/components/TodaysPage.vue +++ b/src/components/TodaysPage.vue @@ -1,10 +1,8 @@ @@ -47,7 +45,7 @@ h1 { .wines-container { display: flex; flex-wrap: wrap; - justify-content: space-between; + justify-content: space-evenly; margin: 0 2rem; @media (min-width: 1500px) { diff --git a/src/components/WinnerPage.vue b/src/components/WinnerPage.vue index 434f9d7..adf9489 100644 --- a/src/components/WinnerPage.vue +++ b/src/components/WinnerPage.vue @@ -2,23 +2,18 @@

Gratulerer {{name}}!

-

Her er valgene for dagens lotteri, du har 10 minutter å velge etter du fikk SMS-en.

+

+ Her er valgene for dagens lotteri, du har 10 minutter å velge etter du fikk SMS-en. +

Finner ikke noen vinner her..

Du må vente på tur..

-
-
- + + +
@@ -64,7 +59,7 @@ export default { this.wines = await _wines.json(); }, methods: { - chosenWine: async function(name) { + chooseWine: async function(name) { let posted = await postWineChosen(this.id, name); console.log("response", posted); if (posted.success) { @@ -93,9 +88,14 @@ export default { flex-direction: column; } +.select-wine { + margin-top: 1rem; +} + .wines-container { - justify-content: center; display: flex; - flex-direction: column; + flex-wrap: wrap; + justify-content: space-evenly; + align-items: flex-start; } \ No newline at end of file From dc7ffbae7a5f5f3b8b694ac65eac3a9fc1e56ed5 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 16:34:37 +0200 Subject: [PATCH 32/59] Removed unused css. --- src/ui/Wine.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/Wine.vue b/src/ui/Wine.vue index 9c31a1b..88574e8 100644 --- a/src/ui/Wine.vue +++ b/src/ui/Wine.vue @@ -88,7 +88,6 @@ h2 { .bottom-section { width: 100%; margin-top: 1rem; - background-color: NavajoWhite; .link { color: $matte-text-color; From 6670f43b11ed80af26449bf9cb29453fda0c42c4 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 17:43:56 +0200 Subject: [PATCH 33/59] Implements intersectObserver to lazy load images. IntersectionObserver for delaying the load of images until the component enteres the viewport. --- src/ui/Wine.vue | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/ui/Wine.vue b/src/ui/Wine.vue index 88574e8..971acfe 100644 --- a/src/ui/Wine.vue +++ b/src/ui/Wine.vue @@ -2,7 +2,7 @@
Wine image @@ -32,6 +32,29 @@ export default { type: Object, required: true } + }, + data() { + return { + loadImage: false + } + }, + methods: { + setImage(entries) { + const { target, isIntersecting } = entries[0]; + if (!isIntersecting) return; + + this.loadImage = true; + this.observer.unobserve(target); + } + }, + created() { + this.observer = new IntersectionObserver(this.setImage, { + root: this.$el, + threshold: 0 + }) + }, + mounted() { + this.observer.observe(this.$el); } }; From 587239b799b7043ec497b874316c04169650ebc8 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 17:56:59 +0200 Subject: [PATCH 34/59] All wines simplified. Refactor script and template. --- src/components/AllWinesPage.vue | 193 ++++++++++++++------------------ 1 file changed, 82 insertions(+), 111 deletions(-) diff --git a/src/components/AllWinesPage.vue b/src/components/AllWinesPage.vue index f042fbd..24cad15 100644 --- a/src/components/AllWinesPage.vue +++ b/src/components/AllWinesPage.vue @@ -1,26 +1,32 @@ @@ -30,6 +36,7 @@ import { page, event } from "vue-analytics"; import Banner from "@/ui/Banner"; import Wine from "@/ui/Wine"; import { overallWineStatistics } from "@/api"; +import { dateString } from "@/utils"; export default { components: { @@ -41,133 +48,97 @@ export default { wines: [] }; }, + methods: { + winDateUrl(date) { + const timestamp = new Date(date).getTime(); + return `/history/${timestamp}` + }, + dateString: dateString + }, async mounted() { - const wines = await overallWineStatistics(); - this.wines = wines.sort((a, b) => - a.rating > b.rating ? -1 : 1 - ); + this.wines = await overallWineStatistics(); } }; From a7d673026ec18406ec98940b9cfe300fd058c795 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 18:11:12 +0200 Subject: [PATCH 35/59] Added missing space before rating. --- src/ui/Wine.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/Wine.vue b/src/ui/Wine.vue index 971acfe..955bdcd 100644 --- a/src/ui/Wine.vue +++ b/src/ui/Wine.vue @@ -10,7 +10,7 @@

{{ wine.name }}

- Rating:{{ wine.rating }} rating + Rating: {{ wine.rating }} rating Pris: {{ wine.price }} NOK Land: {{ wine.country }}
From 9c1b2902193b6bd47861165eeaa9bc4e6c0b5ebf Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 18:11:44 +0200 Subject: [PATCH 36/59] Make sure date is date in dateString(). --- src/utils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/utils.js b/src/utils.js index 7644e4b..b057bca 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,8 @@ const dateString = (date) => { + if (typeof(date) == "string") { + date = new Date(date); + } const ye = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(date) const mo = new Intl.DateTimeFormat('en', { month: '2-digit' }).format(date) const da = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(date) From f2989d2534c13fa87f23391763907453de0dd5d6 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 18:14:43 +0200 Subject: [PATCH 37/59] Use api.js funcs over manual fetch. --- src/components/TodaysPage.vue | 4 ++-- src/components/WinnerPage.vue | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/TodaysPage.vue b/src/components/TodaysPage.vue index 0dfdf12..de81fc1 100644 --- a/src/components/TodaysPage.vue +++ b/src/components/TodaysPage.vue @@ -11,6 +11,7 @@ diff --git a/src/components/WinnerPage.vue b/src/components/WinnerPage.vue index 434f9d7..c60472c 100644 --- a/src/components/WinnerPage.vue +++ b/src/components/WinnerPage.vue @@ -29,7 +29,7 @@ @@ -67,19 +80,8 @@ ol { counter-reset: item; & > li { padding: 2.5px 0; - width: max-content; margin: 0 0 0 -1.25rem; - padding: 0; list-style-type: none; - counter-increment: item; - &:before { - display: inline-block; - width: 1em; - padding-right: 0.5rem; - font-weight: bold; - text-align: right; - content: counter(item) "."; - } @include mobile { padding: 5px 0; From d6839dd10b03c1ea4d6dda4e447baf20e9f03d60 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 19:09:59 +0200 Subject: [PATCH 43/59] Fixed ambiguous null check --- src/components/PersonalHighscorePage.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PersonalHighscorePage.vue b/src/components/PersonalHighscorePage.vue index 69610cd..a925112 100644 --- a/src/components/PersonalHighscorePage.vue +++ b/src/components/PersonalHighscorePage.vue @@ -66,7 +66,7 @@ export default { }, beforeRouteEnter(to, from, next) { next(vm => { - if (from.name !== null) + if (from.name != null) vm.previousRoute = from }) }, From 20136758021852f9b97d9298c36129fad467920d Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 19:10:15 +0200 Subject: [PATCH 44/59] Re-added named routes. --- src/router.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/router.js b/src/router.js index 78064b4..deea0ba 100644 --- a/src/router.js +++ b/src/router.js @@ -20,30 +20,37 @@ import AllRequestedWines from "@/components/AllRequestedWines"; const routes = [ { path: "*", + name: "Hjem", component: VinlottisPage }, { path: "/lottery", + name: "Lotteri", component: LotteryPage }, { path: "/dagens", + name: "Dagens vin", component: TodaysPage }, { path: "/viner", + name: "All viner", component: AllWinesPage }, { path: "/login", + name: "Login", component: LoginPage }, { path: "/create", + name: "Registrer", component: CreatePage }, { path: "/admin", + name: "Admin side", component: AdminPage }, { @@ -53,25 +60,35 @@ const routes = [ { path: "/winner/:id", component: WinnerPage + }, + { + path: "/history/:date", + name: "Historie for dato", + component: HistoryPage }, { path: "/history", + name: "Historie", component: HistoryPage }, { path: "/highscore/:name", + name: "Personlig topplisten", component: PersonalHighscorePage }, { path: "/highscore", + name: "Topplisten", component: HighscorePage }, { path: "/request", + name: "Etterspør vin", component: RequestWine }, { path: "/requested-wines", + name: "Etterspurte vin", component: AllRequestedWines } ]; From 25823540ff0294c6f9df995086078c7c9af5d14a Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 19:24:18 +0200 Subject: [PATCH 45/59] Update background-colors to new primary color. --- src/Vinlottis.vue | 2 +- src/templates/Create.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Vinlottis.vue b/src/Vinlottis.vue index 5843b9b..d0063a7 100644 --- a/src/Vinlottis.vue +++ b/src/Vinlottis.vue @@ -96,7 +96,7 @@ export default { } body { - background-color: #dbeede; + background-color: $primary; } diff --git a/src/templates/Create.html b/src/templates/Create.html index df03739..56aa835 100644 --- a/src/templates/Create.html +++ b/src/templates/Create.html @@ -44,7 +44,7 @@ color="#23101f" /> - + Date: Sun, 11 Oct 2020 19:26:08 +0200 Subject: [PATCH 46/59] Also lowercase query in highscorePage. --- src/components/HighscorePage.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/HighscorePage.vue b/src/components/HighscorePage.vue index 3b9bf8d..c859be8 100644 --- a/src/components/HighscorePage.vue +++ b/src/components/HighscorePage.vue @@ -53,6 +53,7 @@ export default { let val = this.filterInput; if (val.length) { + val = val.toLowerCase() const nameIncludesString = (person) => person.name.toLowerCase().includes(val); highscore = highscore.filter(nameIncludesString) } From 795f110e1b8f8da212713192dfa0b4a56a5eb100 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 22:18:37 +0200 Subject: [PATCH 47/59] Syntax error w/ capitalization crashes draw! --- api/virtualRegistration.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/api/virtualRegistration.js b/api/virtualRegistration.js index 74fb652..533dd1d 100644 --- a/api/virtualRegistration.js +++ b/api/virtualRegistration.js @@ -95,15 +95,19 @@ const registerWinnerSelection = async (req, res) => { })) }; -const chooseLastWineForUser = (winner, prelotteryWine) => { +const chooseLastWineForUser = (winner, preLotteryWine) => { let date = new Date(); date.setHours(5, 0, 0, 0); return _wineFunctions.findSaveWine(preLotteryWine) .then(wonWine => _personFunctions.findSavePerson(winner, wonWine, date)) - .then(() => prelotteryWine.delete()) + .then(() => preLotteryWine.delete()) .then(() => Message.sendLastWinnerMessage(winner, preLotteryWine)) - .then(() => winner.delete()); + .then(() => winner.delete()) + .catch(err => { + console.log("Error thrown from chooseLastWineForUser: " + err); + throw err; + }) } const findAndNotifyNextWinner = async () => { From 439191008a5e2180fc1061ee776ec2a2e86a2609 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 22:18:59 +0200 Subject: [PATCH 48/59] More logging to console during draw. --- api/virtualRegistration.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/virtualRegistration.js b/api/virtualRegistration.js index 533dd1d..8cf204e 100644 --- a/api/virtualRegistration.js +++ b/api/virtualRegistration.js @@ -117,10 +117,13 @@ const findAndNotifyNextWinner = async () => { let winesLeft = await PreLotteryWine.find(); if (winnersLeft.length > 1) { + console.log("multiple winners left, choose next in line") nextWinner = winnersLeft[0]; // multiple winners left, choose next in line } else if (winnersLeft.length == 1 && winesLeft.length > 1) { + console.log("one winner left, but multiple wines") nextWinner = winnersLeft[0] // one winner left, but multiple wines } else if (winnersLeft.length == 1 && winesLeft.length == 1) { + console.log("one winner and one wine left, choose for user") nextWinner = winnersLeft[0] // one winner and one wine left, choose for user wine = winesLeft[0] return chooseLastWineForUser(nextWinner, wine); From b3b5e87ab5e032b34ffd256d6ffb253cf4e93bcd Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 22:19:25 +0200 Subject: [PATCH 49/59] Log gateway response data. --- api/message.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/message.js b/api/message.js index a763a7b..82393ff 100644 --- a/api/message.js +++ b/api/message.js @@ -82,7 +82,11 @@ async function gatewayRequest(body) { res.setEncoding('utf8'); if (res.statusCode == 200) { - res.on("data", (d) => resolve(JSON.parse(d))); + res.on("data", (data) => { + console.log("Response from message gateway:", data) + + resolve(JSON.parse(data)) + }); } else { res.on("data", (data) => { data = JSON.parse(data); From e76e814877981cb904d31dba6642e626836cdc03 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 22:20:09 +0200 Subject: [PATCH 50/59] Always return success bool from getWinner endpoint --- api/virtualLottery.js | 5 ++++- src/components/VirtualLotteryRegistrationPage.vue | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/api/virtualLottery.js b/api/virtualLottery.js index e9ec85f..74224d6 100644 --- a/api/virtualLottery.js +++ b/api/virtualLottery.js @@ -187,7 +187,10 @@ const drawWinner = async (req, res) => { ); await newWinnerElement.save(); - return res.json(winner); + return res.json({ + success: true, + winner + }); }; const finish = async (req, res) => { diff --git a/src/components/VirtualLotteryRegistrationPage.vue b/src/components/VirtualLotteryRegistrationPage.vue index 153c6e9..24145a1 100644 --- a/src/components/VirtualLotteryRegistrationPage.vue +++ b/src/components/VirtualLotteryRegistrationPage.vue @@ -229,7 +229,8 @@ export default { this.drawingWinner = true; let response = await getVirtualWinner(); - if (response) { + if (response.success) { + console.log("Winner:", response.winner); if (this.currentWinners < this.numberOfWinners) { this.countdown(); } else { @@ -245,7 +246,7 @@ export default { this.getAttendees(); } else { this.drawingWinner = false; - alert("Noe gikk galt under trekningen..!"); + alert("Noe gikk galt under trekningen..! " + response["message"]); } } }, From 7e0d3cd75e4081c062e982001aeb37523535d812 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 22:28:31 +0200 Subject: [PATCH 51/59] Text update: sendLastWinnerMessage. Specified where to pick up wone wine. --- api/message.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/message.js b/api/message.js index a763a7b..1451a4b 100644 --- a/api/message.js +++ b/api/message.js @@ -23,7 +23,7 @@ async function sendLastWinnerMessage(winnerObject, wineObject) { return sendMessageToUser( winnerObject.phoneNumber, - `Gratulerer som heldig vinner av vinlotteriet ${winnerObject.name}! Du har vunnet vinen ${wineObject.name}, og vil få nærmere info om hvordan/hvor du kan hente vinen snarest. Ha en ellers fin helg!` + `Gratulerer som heldig vinner av vinlotteriet ${winnerObject.name}! Du har vunnet vinen ${wineObject.name}, vinen kan hentes hos ${ config.name } på kontoret. Ha en ellers fin helg!` ); } From 6603fc489c8d6bb27005021b7908071e1b490524 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 11 Oct 2020 22:32:32 +0200 Subject: [PATCH 52/59] Send confirmation after select wine & text update. Text update: sendWineConfirmation. Confirmation on what wine recipient selected, date wone and where to pick up the wine. --- api/message.js | 18 ++++++++++++++++++ api/virtualRegistration.js | 1 + 2 files changed, 19 insertions(+) diff --git a/api/message.js b/api/message.js index 1451a4b..e2cda4e 100644 --- a/api/message.js +++ b/api/message.js @@ -2,6 +2,17 @@ const https = require("https"); const path = require("path"); const config = require(path.join(__dirname + "/../config/defaults/lottery")); +const dateString = (date) => { + if (typeof(date) == "string") { + date = new Date(date); + } + const ye = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(date) + const mo = new Intl.DateTimeFormat('en', { month: '2-digit' }).format(date) + const da = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(date) + + return `${da}-${mo}-${ye}` +} + async function sendWineSelectMessage(winnerObject) { winnerObject.timestamp_sent = new Date().getTime(); winnerObject.timestamp_limit = new Date().getTime() * 600000; @@ -15,6 +26,12 @@ async function sendWineSelectMessage(winnerObject) { ) } +async function sendWineConfirmation(winnerObject, wineObject, date) { + date = dateString(date); + return sendMessageToUser(winnerObject.phoneNumber, + `Bekreftelse på din vin ${ winnerObject.name }.\nDato vunnet: ${ date }.\nVin valgt: ${ wineObject.name }.\nKan hentes hos ${ config.name } på kontoret. Ha en ellers fin helg!`) +} + async function sendLastWinnerMessage(winnerObject, wineObject) { console.log(`User ${winnerObject.id} is only one left, chosing wine for him/her.`); winnerObject.timestamp_sent = new Date().getTime(); @@ -103,6 +120,7 @@ async function gatewayRequest(body) { module.exports = { sendWineSelectMessage, + sendWineConfirmation, sendLastWinnerMessage, sendWineSelectMessageTooLate, sendInitialMessageToWinners diff --git a/api/virtualRegistration.js b/api/virtualRegistration.js index 74fb652..be34db1 100644 --- a/api/virtualRegistration.js +++ b/api/virtualRegistration.js @@ -80,6 +80,7 @@ const registerWinnerSelection = async (req, res) => { let wonWine = await _wineFunctions.findSaveWine(prelotteryWine); await prelotteryWine.delete(); await _personFunctions.findSavePerson(foundWinner, wonWine, date); + await Message.sendWineConfirmation(foundWinner, wonWine, date); await foundWinner.delete(); console.info("Saved winners choice."); From da00c7735e2b54da96ebf282ab3f5945a788b604 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Mon, 12 Oct 2020 00:05:34 +0200 Subject: [PATCH 53/59] Moved duplicate container & h1 styling to global. --- src/components/AllWinesPage.vue | 22 +------------------ src/components/GeneratePage.vue | 19 +++++++---------- src/components/HighscorePage.vue | 19 ----------------- src/components/PersonalHighscorePage.vue | 18 ---------------- src/components/VinlottisPage.vue | 7 +++++- src/components/WinnerPage.vue | 5 +++++ src/styles/global.scss | 27 ++++++++++++++++++++++++ src/ui/RaffleGenerator.vue | 8 +------ 8 files changed, 48 insertions(+), 77 deletions(-) diff --git a/src/components/AllWinesPage.vue b/src/components/AllWinesPage.vue index 24cad15..e4c63ec 100644 --- a/src/components/AllWinesPage.vue +++ b/src/components/AllWinesPage.vue @@ -66,23 +66,7 @@ export default { @import "./src/styles/variables"; .container { - width: 90vw; - margin: 3rem auto; - margin-bottom: 0; - padding-bottom: 4rem; -} - -h1 { - font-size: 3rem; - font-family: "knowit"; - font-weight: normal; - - font-family: knowit, Arial; - margin-bottom: 25px; -} - -.label { - font-weight: 600; + max-width: unset; } #wines-container { @@ -91,10 +75,6 @@ h1 { justify-content: space-evenly; align-items: flex-start; - @include desktop { - margin: 0 2rem; - } - > div { justify-content: flex-start; } diff --git a/src/components/GeneratePage.vue b/src/components/GeneratePage.vue index e149888..037a03d 100644 --- a/src/components/GeneratePage.vue +++ b/src/components/GeneratePage.vue @@ -1,6 +1,6 @@