Users can change their newsletter subscription status in the settings view.master
@@ -37,6 +37,7 @@ v-else-if="active == 3" | |||||
:token="token" | :token="token" | ||||
@updateAvatar="updateAvatar" | @updateAvatar="updateAvatar" | ||||
@updateLetterhead="updateLetterhead" | @updateLetterhead="updateLetterhead" | ||||
@updateUser="updateUser" | |||||
v-else-if="active == 4" /> | v-else-if="active == 4" /> | ||||
<biller v-if="invalidSub" :user="user"/> | <biller v-if="invalidSub" :user="user"/> | ||||
@@ -182,6 +183,10 @@ function updateLetterhead() { | |||||
getLetterhead(token).then(b => this.user.letterhead = b) | getLetterhead(token).then(b => this.user.letterhead = b) | ||||
} | } | ||||
function updateUser() { | |||||
this.getUser() | |||||
} | |||||
function getFees() { | function getFees() { | ||||
const token = getCookie("skouter") | const token = getCookie("skouter") | ||||
@@ -296,6 +301,7 @@ export default { | |||||
updateLetterhead, | updateLetterhead, | ||||
getLetterhead, | getLetterhead, | ||||
downloadEstimate, | downloadEstimate, | ||||
updateUser, | |||||
}, | }, | ||||
data() { | data() { | ||||
return { | return { | ||||
@@ -51,6 +51,16 @@ | |||||
<button @click="saveProfile">Save</button> | <button @click="saveProfile">Save</button> | ||||
</section> | </section> | ||||
<section class="form inputs special"> | |||||
<h3>Subscriptions</h3> | |||||
<label for="">Standard Plan ($49/month)</label> | |||||
<button @click="unsubscribe">Unsubscribe</button> | |||||
<label for="">Newsletter</label> | |||||
<button @click="changeNewsSub"> | |||||
{{props.user.newsletter ? "Unsubscribe" : "Subscribe"}} | |||||
</button> | |||||
</section> | |||||
<section class="form inputs special"> | <section class="form inputs special"> | ||||
<h3>Reset Password</h3> | <h3>Reset Password</h3> | ||||
<label for="">Old Password</label> | <label for="">Old Password</label> | ||||
@@ -93,7 +103,7 @@ const locationsId = ref(null) | |||||
const addresses = ref([]) | const addresses = ref([]) | ||||
const address = ref({}) | const address = ref({}) | ||||
const props = defineProps(['user', 'token']) | const props = defineProps(['user', 'token']) | ||||
const emit = defineEmits(['updateAvatar', 'updateLetterhead']) | const emit = defineEmits(['updateAvatar', 'updateLetterhead', 'updateUser']) | ||||
const user = Object.assign({}, props.user) | const user = Object.assign({}, props.user) | ||||
function save() { | function save() { | ||||
@@ -268,6 +278,20 @@ function getLocations(e) { | |||||
}) | }) | ||||
} | } | ||||
function unsubscribe() { | |||||
} | |||||
function changeNewsSub() { | |||||
fetch(`/api/user/newsletter`, | |||||
{method: 'GET', | |||||
headers: { | |||||
"Accept": "application/json", | |||||
"Authorization": `Bearer ${props.token}`, | |||||
}, | |||||
}).then(resp => { | |||||
if (resp.ok) emit('updateUser') | |||||
}) | |||||
} | |||||
watch(props.user, (u) => { | watch(props.user, (u) => { | ||||
if (props.user.avatar) { | if (props.user.avatar) { | ||||
@@ -51,6 +51,11 @@ | |||||
<div><label>NMLS ID</label><input type="text" name="nmls"/></div> | <div><label>NMLS ID</label><input type="text" name="nmls"/></div> | ||||
<div id="newsletter"> | |||||
<label>Monthly Newsletter</label> | |||||
<input type="checkbox" name="newsletter" v-model="user.newsletter"/> | |||||
</div> | |||||
<div><span class="error">{{err}}</span></div> | <div><span class="error">{{err}}</span></div> | ||||
<div> | <div> | ||||
@@ -64,7 +69,7 @@ import { ref } from "vue" | |||||
import Dropdown from "./dropdown.vue" | import Dropdown from "./dropdown.vue" | ||||
const addresses = ref([]) | const addresses = ref([]) | ||||
const user = ref({country: "USA", title: "Loan Officer"}) | const user = ref({country: "USA", title: "Loan Officer", newsletter: true}) | ||||
const address = ref({}) | const address = ref({}) | ||||
const locationsId = ref(null) | const locationsId = ref(null) | ||||
const props = defineProps(['err']) | const props = defineProps(['err']) | ||||
@@ -133,4 +138,9 @@ span.error { | |||||
color: darkred; | color: darkred; | ||||
} | } | ||||
div#newsletter { | |||||
justify-content: normal; | |||||
gap: 30px; | |||||
} | |||||
</style> | </style> |
@@ -93,6 +93,7 @@ type User struct { | |||||
Role string `json:"role"` | Role string `json:"role"` | ||||
Password string `json:"password,omitempty"` | Password string `json:"password,omitempty"` | ||||
CustomerId string `json:"customerId"` | CustomerId string `json:"customerId"` | ||||
Newsletter bool `json:"newsletter"` | |||||
} | } | ||||
type License struct { | type License struct { | ||||
@@ -1192,6 +1193,7 @@ func queryUser(db *sql.DB, id int) (User, error) { | |||||
u.role, | u.role, | ||||
u.address, | u.address, | ||||
u.phone, | u.phone, | ||||
u.newsletter, | |||||
coalesce(s.id, 0) | coalesce(s.id, 0) | ||||
FROM user u | FROM user u | ||||
LEFT JOIN subscription s | LEFT JOIN subscription s | ||||
@@ -1218,6 +1220,7 @@ func queryUser(db *sql.DB, id int) (User, error) { | |||||
&user.Role, | &user.Role, | ||||
&user.Address.Id, | &user.Address.Id, | ||||
&user.Phone, | &user.Phone, | ||||
&user.Newsletter, | |||||
&user.Sub.Id, | &user.Sub.Id, | ||||
) | ) | ||||
@@ -1511,6 +1514,7 @@ func insertUser(db *sql.DB, user User) (int, error) { | |||||
country, | country, | ||||
branch_id, | branch_id, | ||||
phone, | phone, | ||||
newsletter, | |||||
created, | created, | ||||
last_login | last_login | ||||
) | ) | ||||
@@ -1533,6 +1537,7 @@ func insertUser(db *sql.DB, user User) (int, error) { | |||||
user.Country, | user.Country, | ||||
user.Branch.Id, | user.Branch.Id, | ||||
user.Phone, | user.Phone, | ||||
user.Newsletter, | |||||
) | ) | ||||
err = row.Scan(&id) | err = row.Scan(&id) | ||||
@@ -1882,6 +1887,19 @@ func setPassword(db *sql.DB, id int, pass string) error { | |||||
return nil | return nil | ||||
} | } | ||||
func (user *User) changeNewsSub(db *sql.DB, isSubed bool) error { | |||||
query := `UPDATE user | |||||
SET newsletter = ? | |||||
WHERE user.id = ? | |||||
` | |||||
_, err := db.Exec(query, isSubed, user.Id) | |||||
if err != nil { | |||||
return errors.New("Could not change newsletter subscription.") | |||||
} | |||||
return nil | |||||
} | |||||
func changePassword(w http.ResponseWriter, db *sql.DB, r *http.Request) { | func changePassword(w http.ResponseWriter, db *sql.DB, r *http.Request) { | ||||
var pass Password | var pass Password | ||||
claim, err := getClaims(r) | claim, err := getClaims(r) | ||||
@@ -1904,6 +1922,22 @@ func changePassword(w http.ResponseWriter, db *sql.DB, r *http.Request) { | |||||
} | } | ||||
} | } | ||||
func toggleNewsSub(w http.ResponseWriter, db *sql.DB, r *http.Request) { | |||||
claim, err := getClaims(r) | |||||
user, err := queryUser(db, claim.Id) | |||||
if err != nil { | |||||
http.Error(w, "Bad fields.", 422) | |||||
return | |||||
} | |||||
err = user.changeNewsSub(db, !user.Newsletter) | |||||
if err != nil { | |||||
http.Error(w, err.Error(), 500) | |||||
return | |||||
} | |||||
} | |||||
func fetchAvatar(db *sql.DB, user int) ([]byte, error) { | func fetchAvatar(db *sql.DB, user int) ([]byte, error) { | ||||
var img []byte | var img []byte | ||||
var query string | var query string | ||||
@@ -3668,6 +3702,10 @@ func api(w http.ResponseWriter, r *http.Request) { | |||||
r.Method == http.MethodPost && | r.Method == http.MethodPost && | ||||
guard(r, 1): | guard(r, 1): | ||||
trialSubscribe(w, db, r) | trialSubscribe(w, db, r) | ||||
case match(p, "/api/user/newsletter", &args) && | |||||
r.Method == http.MethodGet && | |||||
guard(r, 1): | |||||
toggleNewsSub(w, db, r) | |||||
case match(p, "/api/fees", &args) && | case match(p, "/api/fees", &args) && | ||||
r.Method == http.MethodGet && | r.Method == http.MethodGet && | ||||
guard(r, 1): | guard(r, 1): | ||||