mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
feat(wip): polish settings ui for subscriptions
This commit is contained in:
parent
0e83ab02fa
commit
ebcf87ea93
@ -145,6 +145,7 @@ You can specify configuration options either via a config file (default: `config
|
||||
| `app.heartbeat_max_age /`<br>`WAKAPI_HEARTBEAT_MAX_AGE` | `4320h` | Maximum acceptable age of a heartbeat (see [`ParseDuration`](https://pkg.go.dev/time#ParseDuration)) |
|
||||
| `app.custom_languages` | - | Map from file endings to language names |
|
||||
| `app.avatar_url_template` /<br>`WAKAPI_AVATAR_URL_TEMPLATE` | (see [`config.default.yml`](config.default.yml)) | URL template for external user avatar images (e.g. from [Dicebear](https://dicebear.com) or [Gravatar](https://gravatar.com)) |
|
||||
| `app.support_contact` /<br>`WAKAPI_SUPPORT_CONTACT` | `hostmaster@wakapi.dev` | E-Mail address to display as a support contact on the page |
|
||||
| `server.port` /<br> `WAKAPI_PORT` | `3000` | Port to listen on |
|
||||
| `server.listen_ipv4` /<br> `WAKAPI_LISTEN_IPV4` | `127.0.0.1` | IPv4 network address to listen on (leave blank to disable IPv4) |
|
||||
| `server.listen_ipv6` /<br> `WAKAPI_LISTEN_IPV6` | `::1` | IPv6 network address to listen on (leave blank to disable IPv6) |
|
||||
|
@ -79,6 +79,7 @@ type appConfig struct {
|
||||
CountCacheTTLMin int `yaml:"count_cache_ttl_min" default:"30" env:"WAKAPI_COUNT_CACHE_TTL_MIN"`
|
||||
DataRetentionMonths int `yaml:"data_retention_months" default:"-1" env:"WAKAPI_DATA_RETENTION_MONTHS"`
|
||||
AvatarURLTemplate string `yaml:"avatar_url_template" default:"api/avatar/{username_hash}.svg" env:"WAKAPI_AVATAR_URL_TEMPLATE"`
|
||||
SupportContact string `yaml:"support_contact" default:"hostmaster@wakapi.dev" env:"WAKAPI_SUPPORT_CONTACT"`
|
||||
CustomLanguages map[string]string `yaml:"custom_languages"`
|
||||
Colors map[string]map[string]string `yaml:"-"`
|
||||
}
|
||||
|
@ -3,15 +3,17 @@ package view
|
||||
import "github.com/muety/wakapi/models"
|
||||
|
||||
type SettingsViewModel struct {
|
||||
User *models.User
|
||||
LanguageMappings []*models.LanguageMapping
|
||||
Aliases []*SettingsVMCombinedAlias
|
||||
Labels []*SettingsVMCombinedLabel
|
||||
Projects []string
|
||||
SubscriptionPrice string
|
||||
ApiKey string
|
||||
Success string
|
||||
Error string
|
||||
User *models.User
|
||||
LanguageMappings []*models.LanguageMapping
|
||||
Aliases []*SettingsVMCombinedAlias
|
||||
Labels []*SettingsVMCombinedLabel
|
||||
Projects []string
|
||||
SubscriptionPrice string
|
||||
DataRetentionMonths int
|
||||
SupportContact string
|
||||
ApiKey string
|
||||
Success string
|
||||
Error string
|
||||
}
|
||||
|
||||
type SettingsVMCombinedAlias struct {
|
||||
|
@ -740,14 +740,16 @@ func (h *SettingsHandler) buildViewModel(r *http.Request) *view.SettingsViewMode
|
||||
}
|
||||
|
||||
return &view.SettingsViewModel{
|
||||
User: user,
|
||||
LanguageMappings: mappings,
|
||||
Aliases: combinedAliases,
|
||||
Labels: combinedLabels,
|
||||
Projects: projects,
|
||||
ApiKey: user.ApiKey,
|
||||
SubscriptionPrice: subscriptionPrice,
|
||||
Success: r.URL.Query().Get("success"),
|
||||
Error: r.URL.Query().Get("error"),
|
||||
User: user,
|
||||
LanguageMappings: mappings,
|
||||
Aliases: combinedAliases,
|
||||
Labels: combinedLabels,
|
||||
Projects: projects,
|
||||
ApiKey: user.ApiKey,
|
||||
SubscriptionPrice: subscriptionPrice,
|
||||
SupportContact: h.config.App.SupportContact,
|
||||
DataRetentionMonths: h.config.App.DataRetentionMonths,
|
||||
Success: r.URL.Query().Get("success"),
|
||||
Error: r.URL.Query().Get("error"),
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/stripe/stripe-go/v74/webhook"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -41,7 +42,7 @@ func NewSubscriptionHandler(
|
||||
if err != nil {
|
||||
logbuch.Fatal("failed to fetch stripe plan details: %v", err)
|
||||
}
|
||||
config.Subscriptions.StandardPrice = fmt.Sprintf("%2.f €", price.UnitAmountDecimal/100.0) // TODO: respect actual currency
|
||||
config.Subscriptions.StandardPrice = strings.TrimSpace(fmt.Sprintf("%2.f €", price.UnitAmountDecimal/100.0)) // TODO: respect actual currency
|
||||
|
||||
logbuch.Info("enabling subscriptions with stripe payment for %s / month", config.Subscriptions.StandardPrice)
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ let icons = [
|
||||
'mdi:code-json',
|
||||
'mdi:bash',
|
||||
'twemoji:frowning-face',
|
||||
'ci:dot-03-m'
|
||||
]
|
||||
|
||||
const output = path.normalize(path.join(__dirname, '../static/assets/js/icons.dist.js'))
|
||||
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -555,7 +555,7 @@
|
||||
|
||||
<div class="flex flex-wrap md:flex-nowrap mb-8 gap-x-4">
|
||||
<div class="w-full md:w-1/2 mb-4 md:mb-0 inline-block">
|
||||
<label class="font-semibold text-gray-300" for="select-timezone">WakaTime</label>
|
||||
<label class="font-semibold text-gray-300 text-lg" for="select-timezone">WakaTime</label>
|
||||
<span class="block text-sm text-gray-600">
|
||||
You can connect Wakapi with the official WakaTime (or another Wakapi instance, when optionally specifying a custom API URL) in a way that all heartbeats sent to Wakapi are relayed. This way, you can use both services at the same time. To get started, get <a class="link" href="https://wakatime.com/developers#authentication" rel="noopener noreferrer" target="_blank">your API key</a> and paste it here.<br><br>
|
||||
To forward data to another Wakapi instance, use <span class="text-xs font-mono">https://<your-server>/api/compat/wakatime/v1</span> as a URL.<br><br>
|
||||
@ -594,7 +594,7 @@
|
||||
<div class="w-full lg:w-3/4">
|
||||
<div class="flex flex-wrap md:flex-nowrap mb-8 gap-x-4">
|
||||
<div class="w-full md:w-1/2 mb-4 md:mb-0 inline-block">
|
||||
<label class="font-semibold text-gray-300" for="select-timezone">Badges</label>
|
||||
<label class="font-semibold text-gray-300 text-lg" for="select-timezone">Badges</label>
|
||||
<span class="block text-sm text-gray-600">
|
||||
This integration with allows to generate badges for README pages or forums. To enable this feature, you need to grant public, unauthorized access to the respective endpoints. See <a class="link" href="settings#permissions">Permissions</a>. Adapt the URL's <i>label</i> and <i>color</i> parameters for customized badges.<br><br>
|
||||
In addition, there is an endpoint compatible with <a class="link" href="https://shields.io" target="_blank" rel="noreferrer noopener">Shields.IO</a> to allow for even more customization (e.g. different <a class="link" href="https://shields.io/#styles" target="_blank" rel="noreferrer noopener">styles</a>). Only available on public instances, not on localhost.
|
||||
@ -651,7 +651,7 @@
|
||||
<div class="w-full lg:w-3/4">
|
||||
<div class="flex flex-wrap md:flex-nowrap mb-8 gap-x-4">
|
||||
<div class="w-full md:w-1/2 mb-4 md:mb-0 inline-block">
|
||||
<label class="font-semibold text-gray-300" for="select-timezone">GitHub Readme Stats</label>
|
||||
<label class="font-semibold text-gray-300 text-lg" for="select-timezone">GitHub Readme Stats</label>
|
||||
<span class="block text-sm text-gray-600">
|
||||
Wakapi intregrates with <a class="link" href="https://github.com/anuraghazra/github-readme-stats#wakatime-week-stats" target="_blank" rel="noreferrer noopener">GitHub Readme Stats</a> to generate fancy cards for you. To enable this feature, you need to grant public, unauthorized access to the respective endpoints. See <a class="link" href="settings#permissions">Permissions</a>.<br><br>
|
||||
Only available on public instances, not on localhost.
|
||||
@ -676,30 +676,52 @@
|
||||
|
||||
{{ if .SubscriptionsEnabled }}
|
||||
<div v-cloak id="subscription" class="tab flex flex-col space-y-4" v-if="isActive('subscription')">
|
||||
<div class="w-full lg:w-3/4">
|
||||
<div class="w-full lg:w-1/2">
|
||||
<span class="font-semibold text-gray-300 text-lg">Subscription</span>
|
||||
<span class="block text-sm text-gray-600">
|
||||
By default, this Wakapi instance will only store historical coding activity for {{ .DataRetentionMonths }} months.
|
||||
However, if you want to support the project, you can opt for a paid subscription for {{ .SubscriptionPrice }} / month to get unlimited history with no restrictions.
|
||||
You can cancel your subscription at any times!<br>
|
||||
Read more about the idea of adding paid subscriptions to Wakapi <a class="link" href="https://github.com/muety/wakapi" target="_blank" rel="noopener noreferrer">here</a>.<br>
|
||||
</span>
|
||||
<br>
|
||||
|
||||
{{ if not .User.HasActiveSubscription }}
|
||||
<form action="subscription/checkout" method="post" class="flex mb-8" id="form-subscription-checkout">
|
||||
<div class="w-1/2 mr-4 inline-block">
|
||||
<span class="font-semibold text-gray-300">Subscription</span>
|
||||
<span class="block text-sm text-gray-600">
|
||||
By default, this Wakapi instance will only store historical coding activity for 12 months. However, if you want to support the project, you can opt for a paid subscription for {{ .SubscriptionPrice }} / month to get unlimited history with no restrictions.
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-1/2 ml-4 flex items-center">
|
||||
<button type="submit" class="btn-primary ml-1">Subscribe ({{ .SubscriptionPrice }} / mo)</button>
|
||||
</div>
|
||||
<span class="font-semibold text-gray-300">How it works</span>
|
||||
<span class="block text-sm text-gray-600">
|
||||
Without a subscription, your coding activity older than {{ .DataRetentionMonths }} months will get deleted by a routine that is run every day.
|
||||
If you do have an active subscription at the time of checking, your data is kept.<br>
|
||||
In other words, for every point in time <span class="text-xs font-mono">X</span>, where you do not currently have an active subscription, all data older than <span class="text-xs font-mono">X - {{ .DataRetentionMonths }}</span> months gets dropped.
|
||||
</span>
|
||||
<br>
|
||||
<span class="font-semibold text-gray-300">Please note</span>
|
||||
<span class="block text-sm text-gray-600">
|
||||
If you just purchased a subscription, it might take a moment until it's active. Try refresh this page in a minute. Otherwise, please contact <a class="link" href="mailto:{{ .SupportContact }}">{{ .SupportContact }}</a>.
|
||||
</span>
|
||||
<br>
|
||||
{{ end }}
|
||||
|
||||
<span class="block text-sm text-gray-600">
|
||||
Your currently oldest data point is from <span class="text-gray-300 font-semibold">2022-01-01</span>.
|
||||
</span>
|
||||
<br>
|
||||
|
||||
<span class="font-semibold text-gray-300">Subscription status:</span>
|
||||
<span class="text-gray-600 ml-1 text-sm">
|
||||
{{ if .User.HasActiveSubscription }}
|
||||
<span class="font-semibold text-green-500 text-base">Active</span> (until {{ .User.SubscribedUntil.T | date }})
|
||||
{{ else }}
|
||||
<span class="font-semibold text-red-500 text-base">Inactive</span>
|
||||
{{ end }}
|
||||
</span>
|
||||
|
||||
{{ if not .User.HasActiveSubscription }}
|
||||
<form action="subscription/checkout" method="post" class="mt-8 mb-8" id="form-subscription-checkout">
|
||||
<button type="submit" class="btn-primary mt-4">Subscribe ({{ .SubscriptionPrice }} / mo)</button>
|
||||
</form>
|
||||
{{ else }}
|
||||
<form action="subscription/portal" method="post" class="flex mb-8" id="form-subscription-portal">
|
||||
<div class="w-1/2 mr-4 inline-block">
|
||||
<span class="font-semibold text-gray-300">Subscription</span>
|
||||
<span class="block text-sm text-gray-600">
|
||||
Congratulations! You have an active subscription until <strong>{{ .User.SubscribedUntil.T | date }}</strong>.
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-1/2 ml-4 flex items-center">
|
||||
<button type="submit" class="btn-danger ml-1">Cancel subscription</button>
|
||||
</div>
|
||||
<form action="subscription/portal" method="post" class="mt-8 mb-8" id="form-subscription-portal">
|
||||
<button type="submit" class="btn-danger">Cancel subscription</button>
|
||||
</form>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user