Browse Source

Render and select address from dropdown

master
Immanuel Onyeka 1 year ago
parent
commit
1d7163f5ae
8 changed files with 132 additions and 13 deletions
  1. +32
    -0
      components/dropdown.vue
  2. +60
    -1
      components/settings.vue
  3. +0
    -9
      config.default.go
  4. +1
    -0
      migrations/0_29092022_setup_tables.sql
  5. +34
    -0
      package-lock.json
  6. +1
    -0
      package.json
  7. +1
    -1
      skouter.go
  8. +3
    -2
      webpack.config.js

+ 32
- 0
components/dropdown.vue View File

@@ -0,0 +1,32 @@
<template>
<div class="entries">
<span class="entry" v-for="entry in entries"
@click="$emit('select', entry.value)"
>{{entry.text}}</span>
</div>
</template>

<style scoped>
.entries {
display: flex;
flex-flow: column;
position: absolute;
left: 0;
background: var(--secondary-bg);
width: 100%;
margin-top: 5px;
z-index: 3;
border: 1px solid black;
}
.entry {
border-bottom: 1px solid var(--text);
padding: 5px;
cursor: pointer;
}
</style>

<script setup>
const props = defineProps(['entries'])
const emits = defineEmits(['select'])
</script>

+ 60
- 1
components/settings.vue View File

@@ -38,6 +38,16 @@
<option value="Canada">Canada</option> <option value="Canada">Canada</option>
</select> </select>


<div class="address-entry">
<label for="">Address</label>
<input type="text" @input="searchLocation" :value="address.full">
<dropdown v-if="addresses && addresses.length"
:entries="addresses.map(a => ({text: a.full_address, value: a}))"
@select="setAddress"
>
</dropdown>
</div>

<button @click="saveProfile">Save</button> <button @click="saveProfile">Save</button>
</section> </section>


@@ -67,6 +77,7 @@
<script setup> <script setup>
import { ref, watch, onMounted } from "vue" import { ref, watch, onMounted } from "vue"
import Dialog from "./dialog.vue" import Dialog from "./dialog.vue"
import Dropdown from "./dropdown.vue"


let avatar = ref(null) // the canvas element let avatar = ref(null) // the canvas element
let letterhead = ref(null) // the canvas element let letterhead = ref(null) // the canvas element
@@ -78,6 +89,9 @@ let passError = ref('')
let oldPass = ref('') let oldPass = ref('')
let newPass = ref('') let newPass = ref('')
let confirmPass = ref('') let confirmPass = ref('')
const locationsId = ref(null)
const addresses = ref([])
const address = ref({})
const props = defineProps(['user', 'token']) const props = defineProps(['user', 'token'])
const emit = defineEmits(['updateAvatar', 'updateLetterhead']) const emit = defineEmits(['updateAvatar', 'updateLetterhead'])
let user = Object.assign({}, props.user) let user = Object.assign({}, props.user)
@@ -176,8 +190,19 @@ function changeLetterhead(blob) {
}) })
} }


function setAddress(a) {
addresses.value = null
address.value = {
full: a.full_address,
street: a.address,
city: a.context.place.name,
region: a.context.region.name,
country: a.context.country.name,
zip: a.context.postcode.name,
}
}

function saveProfile() { function saveProfile() {
console.log(user.firstName)
fetch(`/api/user`, fetch(`/api/user`,
{method: 'PATCH', {method: 'PATCH',
body: JSON.stringify(user), body: JSON.stringify(user),
@@ -216,6 +241,31 @@ function changePassword(f) {
}) })
} }


function searchLocation(e) {
address.value.full = e.target.value
clearTimeout(locationsId.value)
locationsId.value = setTimeout(getLocations, 1000, e)
}

function getLocations(e) {
let prefix = "https://api.mapbox.com/search/searchbox/v1/suggest?"
let search = e.target.value
let key = encodeURIComponent(process.env.MAPBOX_API_KEY)
if (!search) return
fetch(`${prefix}q=${search}&proximity=ip&access_token=${key}&session_token=1`
).then(resp => resp.json()).then(entries => {
if (!entries?.suggestions) {
addresses.value = null
return
}
addresses.value = entries.suggestions.filter(e => e.full_address)
})
}


watch(props.user, (u) => { watch(props.user, (u) => {
if (props.user.avatar) { if (props.user.avatar) {
changeAvatar(props.user.avatar) changeAvatar(props.user.avatar)
@@ -226,4 +276,13 @@ watch(props.user, (u) => {
} }
}, {immediate: true}) }, {immediate: true})


onMounted(() => {
})

</script> </script>

<style scoped>
div.address-entry input {
width: 100%;
}
</style>

+ 0
- 9
config.default.go View File

@@ -1,9 +0,0 @@
/*
package main

var config = map[string]string {
"dbUsername": "",
"dbPassword": "",
}
*/
package main

+ 1
- 0
migrations/0_29092022_setup_tables.sql View File

@@ -2,6 +2,7 @@


CREATE TABLE address ( CREATE TABLE address (
id INT AUTO_INCREMENT, id INT AUTO_INCREMENT,
full VARCHAR(200) UNIQUE NOT NULL,
street VARCHAR(40) UNIQUE NOT NULL, street VARCHAR(40) UNIQUE NOT NULL,
city VARCHAR(40) UNIQUE NOT NULL, city VARCHAR(40) UNIQUE NOT NULL,
region VARCHAR(40) UNIQUE NOT NULL, region VARCHAR(40) UNIQUE NOT NULL,


+ 34
- 0
package-lock.json View File

@@ -11,6 +11,7 @@
}, },
"devDependencies": { "devDependencies": {
"css-loader": "^6.7.1", "css-loader": "^6.7.1",
"dotenv-webpack": "^8.0.1",
"vue-loader": "^17.0.1", "vue-loader": "^17.0.1",
"vue-template-compiler": "^2.7.13", "vue-template-compiler": "^2.7.13",
"webpack": "^5.74.0", "webpack": "^5.74.0",
@@ -1277,6 +1278,39 @@
"integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==", "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==",
"optional": true "optional": true
}, },
"node_modules/dotenv": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/dotenv-defaults": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz",
"integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==",
"dev": true,
"dependencies": {
"dotenv": "^8.2.0"
}
},
"node_modules/dotenv-webpack": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.0.1.tgz",
"integrity": "sha512-CdrgfhZOnx4uB18SgaoP9XHRN2v48BbjuXQsZY5ixs5A8579NxQkmMxRtI7aTwSiSQcM2ao12Fdu+L3ZS3bG4w==",
"dev": true,
"dependencies": {
"dotenv-defaults": "^2.0.2"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"webpack": "^4 || ^5"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",


+ 1
- 0
package.json View File

@@ -9,6 +9,7 @@
}, },
"devDependencies": { "devDependencies": {
"css-loader": "^6.7.1", "css-loader": "^6.7.1",
"dotenv-webpack": "^8.0.1",
"vue-loader": "^17.0.1", "vue-loader": "^17.0.1",
"vue-template-compiler": "^2.7.13", "vue-template-compiler": "^2.7.13",
"webpack": "^5.74.0", "webpack": "^5.74.0",


+ 1
- 1
skouter.go View File

@@ -29,6 +29,7 @@ import (


type Address struct { type Address struct {
Id int `json:"id"` Id int `json:"id"`
Full string `json:"full"`
Street string `json:"street"` Street string `json:"street"`
City string `json:"city"` City string `json:"city"`
Region string `json:"region"` Region string `json:"region"`
@@ -1017,7 +1018,6 @@ func changePassword(w http.ResponseWriter, db *sql.DB, r *http.Request) {
claim, err := getClaims(r) claim, err := getClaims(r)
err = json.NewDecoder(r.Body).Decode(&pass) err = json.NewDecoder(r.Body).Decode(&pass)
if err != nil { http.Error(w, "Bad fields.", 422); return } if err != nil { http.Error(w, "Bad fields.", 422); return }
fmt.Println(pass)
if checkPassword(db, claim.Id, pass.Old) { if checkPassword(db, claim.Id, pass.Old) {
err = setPassword(db, claim.Id, pass.New) err = setPassword(db, claim.Id, pass.New)


+ 3
- 2
webpack.config.js View File

@@ -1,5 +1,6 @@
const { VueLoaderPlugin } = require('vue-loader') const { VueLoaderPlugin } = require('vue-loader')
const path = require('path');
const path = require('path')
const Dotenv = require('dotenv-webpack')


module.exports = { module.exports = {
entry: './main.js', entry: './main.js',
@@ -23,5 +24,5 @@ module.exports = {
} }
}, },
// Required for also applying rules to sections of SFC // Required for also applying rules to sections of SFC
plugins: [new VueLoaderPlugin()],
plugins: [new VueLoaderPlugin(), new Dotenv({systemVars: true})],
}; };

Loading…
Cancel
Save