package h
import (
"bytes"
"fmt"
"html/template"
"io"
"net/url"
"gopkg.awl.red/lx/internal/config"
)
var templateBecome = template.Must(template.New("template_become").Funcs(tmplfuncs).Parse(`<!doctype html>
<html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{.StyleTag}}
<style>
form .cell {
height: 40px;
}
form .cell.price {
height: 74px;
}
form .cell.plan-label {
height: 74px;
}
form .cell.plan {
height: 74px;
display: flex;
flex-flow: column;
align-items: center;
justify-content: flex-start;
}
form .cell.plan label {
font-weight: bold;
padding: 0;
width: initial;
}
#pay-schedule {
display: flex;
justify-content: center;
align-items: center;
}
#pay-schedule .option {
display: flex;
flex-flow: column;
align-items: center;
justify-content: center;
margin: 40px;
}
#pay-schedule .option label {
font-weight: bold;
width: initial;
padding: 0;
}
</style>
</head><body>
{{ $cashEnabled := .Data.CashEnabled }}
{{ $cashStart := .Data.CashPlans.Start }}
{{ $cashMedium := .Data.CashPlans.Medium }}
{{ $cashHigh := .Data.CashPlans.High }}
<title>{{ .Config.Title }} members</title>
<h1>{{ .Config.Title }} members</h1>
<script>
function removeToast(id) {
const el = document.getElementById(id)
if (el) {
el.remove()
}
}
{{ if .Data.DidLogout }}
function removeToastLogout() {
window.history.pushState({}, document.title, window.location.pathname);
removeToast('toast-logout')
}
setTimeout(removeToastLogout, 10000)
{{ end }}
{{ if .Data.BadLogin }}
function removeToastBadLogin() {
removeToast('toast-bad-login')
window.history.pushState({}, document.title, window.location.pathname);
}
setTimeout(removeToastBadLogin, 10000)
{{ end }}
function showPlanPriceSelection(id) {
[...document.querySelectorAll('.price-option')].forEach(function(el) {
fontWeight = 'normal';
if (el.id === id) {
fontWeight = 'bold';
}
el.style.fontWeight = fontWeight;
})
}
window.showPlanPriceSelection = showPlanPriceSelection
// ids are {[p]ay}_{[s]tart|[m]edium|[h]igh}_{m[o]nthly|[a]nnual|[c]ash}
// e.g. high cash is p_h_c
</script>
<noscript>
<style>
.toast {
color: purple;
}
</style>
</noscript>
{{ if .Data.DidLogout }}
<div class="toast" id="toast-logout" onclick="removeToastLogout()" style="position:fixed;top:0;right:0;padding:20px;background:green;">Logged out successfully ❌</div>
{{ end }}
{{ if .Data.BadLogin }}
<div class="toast" id="toast-bad-login" onclick="removeToastBadLogin()" style="position:fixed;top:0;right:0;padding:20px;background:red;">Error logging in ❌</div>
{{ end }}
<details>
<summary><h2 style="display:inline;">Login</h2></summary>
<form id="login" method="post" action="/_ui/login">
<div>
<label for="email">Email: </label>
<input id="email" name="email" type="text" autocomplete="on"></input>
</div>
<div>
<label for="username">Username: </label>
<input id="username" name="username" type="text" autocomplete="on"></input>
</div>
<div>
<label for="password">Password: </label>
<input id="password" name="password" type="password"
{{ if .Config.PasswordRequired }}required{{ end }}
></input>
</div>
<div>
<input id="submit-login" name="submit" type="submit" value="Log in"></input>
</div>
</form>
</details>
<details>
<summary>
<h2 style="display: inline">Sign up</h2>
<p>{{AsHtml .Config.Purpose}}</p>
</summary>
<form id="become" method="post" action="/_ui/become" style="width: 100%; max-width: 1000px;">
<div style="display:block;">
<div id="pay-schedule">
<div class="option">
<label for="pay_monthly">Pay monthly: </label>
<input id="pay_monthly" type="radio" name="pay_schedule" value="monthly">
</div>
<div class="option">
<label for="pay_annual">Pay annual: </label>
<input id="pay_annual" type="radio" name="pay_schedule" value="annual" {{ if not .Data.CashEnabled }}checked{{ end }}>
</div>
{{ if .Data.CashEnabled }}
<div class="option">
<label for="pay_cash_annual">Pay annual (cash): </label>
<input id="pay_cash_annual" type="radio" name="pay_schedule" value="cash_annual" checked>
</div>
{{ end }}
</div>
<div style="display: flex; flex-direction: row;">
<div style="order: 0" style="flex-shrink:0; flex-grow:0;">
<div class="cell plan-label">Plan:</div>
<div class="cell price">Price:</div>
<div class="cell">Anonymous links <span title="e.g. randomized 7 character slug, {{ .Data.Scheme }}://{{ .Data.Host}}/OvuS1xN">(?)</span>:</div>
<div class="cell">Named links <span title="e.g. name of your choice, up to 255 characters, {{ .Data.Scheme }}://{{ .Data.Host}}/MyBusiness">(?)</span>:</div>
<div class="cell">Folders <span title="e.g. reserve all names underneath a slash for logical grouping, e.g. {{ .Data.Scheme }}://{{ .Data.Host }}/mybiz, and only you can create links under it, such as {{ .Data.Scheme }}://{{ .Data.Host }}/mybiz/buy or {{ .Data.Scheme }}://{{ .Data.Host }}/mybiz/blackfriday">(?)</span>:</div>
<div class="cell">Analytics:</div>
<div class="cell">Analytics retention:</div>
<div class="cell">Analytics granularity:</div>
<div class="cell">Analytics View Limits:</div>
<div class="cell">API access <span title="See {{ .Data.Scheme }}://{{ .Data.Host }}/_ui/openapi">(?)</span>:</div>
</div>
{{ range .Config.BusinessTiers }}
{{ if or (le .FeatureLevel 0) (ge .FeatureLevel 9999) }} {{ continue }} {{ end }}
<div style="order: {{.FeatureLevel}}; flex: 1 0 auto;">
<div class="cell plan"><label for="plan-{{.Name}}">{{ .DisplayName }}</label><input type="radio" id="plan-{{.Name}}" name="plan" value="{{.Name}}" {{ if eq .Name "medium"}} checked {{end}}></input></div>
<div class="cell price">
<div class="price-option" id="p_{{L1 .Name}}_m">{{ AsPrice .PriceByMonth}} monthly</div>
<div class="price-option" id="p_{{L1 .Name}}_a">{{ AsPrice .PriceByYear }} annual ({{ AsMonthlyPrice .PriceByYear }}/mo)</div>
{{ if $cashEnabled }}<div class="price-option" id="p_{{L1 .Name}}_c">
{{ $cashPrice := 0 }}
{{ if eq .Name "start" }}{{ AsPrice $cashStart}}{{ $cashPrice = $cashStart }}{{ end }}
{{ if eq .Name "medium" }}{{ AsPrice $cashMedium}}{{ $cashPrice = $cashMedium }}{{ end }}
{{ if eq .Name "high" }}{{ AsPrice $cashHigh}}{{ $cashPrice = $cashHigh }}{{ end }} cash annual ({{ AsMonthlyPrice $cashPrice }}/mo)
</div>{{ end }}</div>
<div class="cell">{{ .BackhalvesAnonymous }}</div>
<div class="cell">{{ .BackhalvesNamed }}</div>
<div class="cell">{{ .Folders }}</div>
<div class="cell">Y</div>
<div class="cell">{{ SecAsD .AnalyticsRetention }} </div>
<div class="cell">{{ SecAsD .AnalyticsMaxGranularity }} </div>
<div class="cell">{{ .AnalyticsViewLimit }} </div>
<div class="cell">Y</div>
</div>
{{ end }}
</div>
<details id="user-account">
<summary><h3 style="display:inline;">User acount</h3></summary>
<div>
<label for="email">Email: </label>
<input id="email" name="email" type="text" required autocomplete="on"></input>
</div>
<div>
<label for="username">Username: </label>
<input id="username" name="username" type="text" required autocomplete="on"></input>
</div>
<div>
<label for="firstname">First name: </label>
<input id="firstname" name="firstname" type="text" required autocomplete="on"></input>
</div>
<div>
<label for="lastname">Last name: </label>
<input id="lastname" name="lastname" type="text" required autocomplete="on"></input>
</div>
<div>
<label for="password">Password: </label>
<input id="password" name="password" type="password" required></input>
</div>
<div>
<label for="password_confirm">Password (Confirm): </label>
<input id="password_confirm" name="password_confirm" type="password" required></input>
</div>
</details>
<details id="business">
<summary><h3 style="display:inline;">business (if applicable) & billing info</h3></summary>
<div>
<label for="business_name">Business name (type N/A if this is for a personal account): </label>
<input id="business_name" name="business_name" type="text" autocomplete="on"></input>
</div>
<div>
<label for="address_line1">Address Line 1: </label>
<input required id="address_line1" name="address_line1" type="text" autocomplete="on"></input>
</div>
<div>
<label for="address_line2">Address Line 2: </label>
<input id="address_line2" name="address_line2" type="text" autocomplete="on"></input>
</div>
<div>
<label for="address_city">City: </label>
<input required id="address_city" name="address_city" type="text" autocomplete="on"></input>
</div>
<div>
<label for="address_state">State: </label>
<input required id="address_state" name="address_state" type="text" autocomplete="on"></input>
</div>
<div>
<label for="address_postal_code">Postal Code: </label>
<input required id="address_postal_code" name="address_postal_code" type="text" autocomplete="on"></input>
</div>
<div>
<label for="address_country">Country: </label>
<input required id="address_country" name="address_country" type="text" autocomplete="on" {{ if .Config.OnlyCountry }}value="{{ .Config.OnlyCountry }}" disabled {{ end }} required></input>
</div>
</details>
<input id="submit-become" name="submit" type="submit" value="Choose plan">
</form>
{{ .Data.Footer }}
<script>
window.showPlanPriceSelection({{ if .Data.CashEnabled }}"p_m_c"{{ else }}"p_m_a"{{ end }})
const becomeForm = document.getElementById('become')
const submitPricing = document.getElementById('submit-become')
let readySubmit = false;
submitPricing.addEventListener('mousedown', function(e) {
readySubmit = true;
})
becomeForm.addEventListener('submit', function(e) {
if (!readySubmit) {
e.preventDefault()
return false
}
})
becomeForm.addEventListener('change', function(e) {
const targetName = e.target.name
if (targetName !== "plan" && targetName !== 'pay_schedule') {
return
}
const valueLetter = e.target.value[0]
const plan = targetName === "plan" ? valueLetter : e.currentTarget.elements["plan"].value[0]
const paySchedule = targetName === "pay_schedule" ? valueLetter : e.currentTarget.elements["pay_schedule"].value[0]
window.showPlanPriceSelection("p_"+plan+"_"+paySchedule)
})
</script>
</body></html>
`))
type TCashPrices struct {
Start int
Medium int
High int
}
type TDataBecome struct {
CashEnabled bool
CashPlans TCashPrices
DidLogout bool
BadLogin bool
Host string
Scheme string
Footer template.HTML
}
func footer(c *config.Config) string {
return fmt.Sprintf(`<footer>Service by <a href="%s">%s</a>.</footer>`, c.CompanyUrl, c.Company)
}
func TBecome(w io.Writer, u url.Values, c *config.Config, data TDataBecome) error {
_, didLogout := u["did_logout"]
_, badLogin := u["bad_login"]
data.DidLogout = didLogout
data.BadLogin = badLogin
data.Footer = template.HTML(footer(c))
var stylesheetBuf bytes.Buffer
templateBaseStylesheet.Execute(&stylesheetBuf, ConfigTemplateData{Config: c})
return templateBecome.Execute(w, ConfigTemplateData{Config: c, StyleTag: template.HTML(stylesheetBuf.String()), Data: data})
}