Users can change their newsletter subscription status in the settings view.master
@@ -37,6 +37,7 @@ v-else-if="active == 3" | |||
:token="token" | |||
@updateAvatar="updateAvatar" | |||
@updateLetterhead="updateLetterhead" | |||
@updateUser="updateUser" | |||
v-else-if="active == 4" /> | |||
<biller v-if="invalidSub" :user="user"/> | |||
@@ -182,6 +183,10 @@ function updateLetterhead() { | |||
getLetterhead(token).then(b => this.user.letterhead = b) | |||
} | |||
function updateUser() { | |||
this.getUser() | |||
} | |||
function getFees() { | |||
const token = getCookie("skouter") | |||
@@ -296,6 +301,7 @@ export default { | |||
updateLetterhead, | |||
getLetterhead, | |||
downloadEstimate, | |||
updateUser, | |||
}, | |||
data() { | |||
return { | |||
@@ -51,6 +51,16 @@ | |||
<button @click="saveProfile">Save</button> | |||
</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"> | |||
<h3>Reset Password</h3> | |||
<label for="">Old Password</label> | |||
@@ -93,7 +103,7 @@ const locationsId = ref(null) | |||
const addresses = ref([]) | |||
const address = ref({}) | |||
const props = defineProps(['user', 'token']) | |||
const emit = defineEmits(['updateAvatar', 'updateLetterhead']) | |||
const emit = defineEmits(['updateAvatar', 'updateLetterhead', 'updateUser']) | |||
const user = Object.assign({}, props.user) | |||
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) => { | |||
if (props.user.avatar) { | |||
@@ -51,6 +51,11 @@ | |||
<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> | |||
@@ -64,7 +69,7 @@ import { ref } from "vue" | |||
import Dropdown from "./dropdown.vue" | |||
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 locationsId = ref(null) | |||
const props = defineProps(['err']) | |||
@@ -133,4 +138,9 @@ span.error { | |||
color: darkred; | |||
} | |||
div#newsletter { | |||
justify-content: normal; | |||
gap: 30px; | |||
} | |||
</style> |
@@ -93,6 +93,7 @@ type User struct { | |||
Role string `json:"role"` | |||
Password string `json:"password,omitempty"` | |||
CustomerId string `json:"customerId"` | |||
Newsletter bool `json:"newsletter"` | |||
} | |||
type License struct { | |||
@@ -1192,6 +1193,7 @@ func queryUser(db *sql.DB, id int) (User, error) { | |||
u.role, | |||
u.address, | |||
u.phone, | |||
u.newsletter, | |||
coalesce(s.id, 0) | |||
FROM user u | |||
LEFT JOIN subscription s | |||
@@ -1218,6 +1220,7 @@ func queryUser(db *sql.DB, id int) (User, error) { | |||
&user.Role, | |||
&user.Address.Id, | |||
&user.Phone, | |||
&user.Newsletter, | |||
&user.Sub.Id, | |||
) | |||
@@ -1511,6 +1514,7 @@ func insertUser(db *sql.DB, user User) (int, error) { | |||
country, | |||
branch_id, | |||
phone, | |||
newsletter, | |||
created, | |||
last_login | |||
) | |||
@@ -1533,6 +1537,7 @@ func insertUser(db *sql.DB, user User) (int, error) { | |||
user.Country, | |||
user.Branch.Id, | |||
user.Phone, | |||
user.Newsletter, | |||
) | |||
err = row.Scan(&id) | |||
@@ -1882,6 +1887,19 @@ func setPassword(db *sql.DB, id int, pass string) error { | |||
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) { | |||
var pass Password | |||
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) { | |||
var img []byte | |||
var query string | |||
@@ -3668,6 +3702,10 @@ func api(w http.ResponseWriter, r *http.Request) { | |||
r.Method == http.MethodPost && | |||
guard(r, 1): | |||
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) && | |||
r.Method == http.MethodGet && | |||
guard(r, 1): | |||