add: ProfileStyle products
This commit is contained in:
parent
077e9252e3
commit
95cb889080
19 changed files with 525 additions and 54 deletions
|
@ -2491,6 +2491,8 @@
|
|||
(text "Create infinite Littleweb sites"))
|
||||
(li
|
||||
(text "Create infinite Littleweb domains"))
|
||||
(li
|
||||
(text "Create and sell CSS snippet products"))
|
||||
|
||||
(text "{% if config.security.enable_invite_codes -%}")
|
||||
(li
|
||||
|
|
|
@ -150,35 +150,60 @@
|
|||
(icon (text "package-check"))
|
||||
(b
|
||||
(str (text "economy:label.fulfillment_style"))))
|
||||
(form
|
||||
(div
|
||||
("class" "card flex flex_col gap_2")
|
||||
("onsubmit" "update_method_from_form(event)")
|
||||
(p (text "If you choose to send an automated mail letter upon purchase, users will automatically receive the message you supply below."))
|
||||
(p (text "If you disable automail, you'll be required to manually mail users who have purchased your product before the transfer is finalized."))
|
||||
(select
|
||||
("id" "fulfillment_style_select")
|
||||
("onchange" "mirror_fulfillment_style_select(true)")
|
||||
(option ("value" "mail") (text "Mail") ("selected" "{{ not product.method == \"ProfileStyle\" }}"))
|
||||
(option ("value" "snippet") (text "CSS Snippet") ("selected" "{{ product.method == \"ProfileStyle\" }}")))
|
||||
(form
|
||||
("class" "flex flex_col gap_2 hidden")
|
||||
("id" "mail_fulfillment")
|
||||
("onsubmit" "update_method_from_form(event)")
|
||||
(p (text "If you choose to send an automated mail letter upon purchase, users will automatically receive the message you supply below."))
|
||||
(p (text "If you disable automail, you'll be required to manually mail users who have purchased your product before the transfer is finalized."))
|
||||
(text "{% set is_automail = product.method != \"ManualMail\" and product.method != \"ProfileStyle\" %}")
|
||||
|
||||
(label
|
||||
("for" "use_automail")
|
||||
("class" "flex items_center gap_2")
|
||||
(input
|
||||
("type" "checkbox")
|
||||
("id" "use_automail")
|
||||
("name" "use_automail")
|
||||
("class" "w_content")
|
||||
("oninput" "mirror_use_automail()")
|
||||
("checked" "{% if product.method != \"ManualMail\" -%} true {%- else -%} false {%- endif %}"))
|
||||
(span
|
||||
(str (text "economy:label.use_automail"))))
|
||||
(div
|
||||
("class" "flex flex_col gap_1")
|
||||
(label
|
||||
("for" "automail_message")
|
||||
(str (text "economy:label.automail_message")))
|
||||
(textarea
|
||||
("name" "automail_message")
|
||||
("id" "automail_message")
|
||||
("placeholder" "automail_message")
|
||||
(text "{% if product.method != \"ManualMail\" -%} {{ product.method.AutoMail }} {%- endif %}")))
|
||||
(button (str (text "general:action.save")))))
|
||||
("for" "use_automail")
|
||||
("class" "flex items_center gap_2")
|
||||
(input
|
||||
("type" "checkbox")
|
||||
("id" "use_automail")
|
||||
("name" "use_automail")
|
||||
("class" "w_content")
|
||||
("oninput" "mirror_use_automail()")
|
||||
("checked" "{% if is_automail -%} true {%- else -%} false {%- endif %}"))
|
||||
(span
|
||||
(str (text "economy:label.use_automail"))))
|
||||
(div
|
||||
("class" "flex flex_col gap_1")
|
||||
(label
|
||||
("for" "automail_message")
|
||||
(str (text "economy:label.automail_message")))
|
||||
(textarea
|
||||
("name" "automail_message")
|
||||
("id" "automail_message")
|
||||
("placeholder" "automail_message")
|
||||
(text "{% if is_automail -%} {{ product.method.AutoMail }} {%- endif %}")))
|
||||
(button (str (text "general:action.save"))))
|
||||
(form
|
||||
("class" "flex flex_col gap_2 hidden")
|
||||
("id" "snippet_fulfillment")
|
||||
("onsubmit" "update_data_from_form(event)")
|
||||
(text "{{ components::supporter_ad(body=\"Become a supporter to create snippets!\") }}")
|
||||
(div
|
||||
("class" "flex flex_col gap_1")
|
||||
(label
|
||||
("for" "data")
|
||||
(str (text "economy:label.snippet_data")))
|
||||
(textarea
|
||||
("name" "data")
|
||||
("id" "data")
|
||||
("placeholder" "data")
|
||||
(text "{{ product.data }}")))
|
||||
(button (str (text "general:action.save"))))))
|
||||
|
||||
(div
|
||||
("class" "flex gap_2")
|
||||
|
@ -347,6 +372,28 @@
|
|||
});
|
||||
}
|
||||
|
||||
async function update_data_from_form(e) {
|
||||
e.preventDefault();
|
||||
await trigger(\"atto::debounce\", [\"products::update\"]);
|
||||
|
||||
fetch(\"/api/v1/products/{{ product.id }}/data\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: e.target.data.value,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
async function delete_product() {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
|
@ -378,7 +425,46 @@
|
|||
}
|
||||
}
|
||||
|
||||
globalThis.mirror_fulfillment_style_select = (send = false) => {
|
||||
const selected = document.getElementById(\"fulfillment_style_select\").selectedOptions[0].value;
|
||||
|
||||
if (selected === \"mail\") {
|
||||
document.getElementById(\"mail_fulfillment\").classList.remove(\"hidden\");
|
||||
document.getElementById(\"snippet_fulfillment\").classList.add(\"hidden\");
|
||||
|
||||
if (send) {
|
||||
update_method_from_form({
|
||||
preventDefault: () => {},
|
||||
target: document.getElementById(\"mail_fulfillment\"),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
document.getElementById(\"mail_fulfillment\").classList.add(\"hidden\");
|
||||
document.getElementById(\"snippet_fulfillment\").classList.remove(\"hidden\");
|
||||
|
||||
if (send) {
|
||||
fetch(\"/api/v1/products/{{ product.id }}/method\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
method: \"ProfileStyle\",
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
mirror_use_automail();
|
||||
mirror_fulfillment_style_select();
|
||||
}, 150);"))
|
||||
(text "{% endblock %}")
|
||||
|
|
|
@ -19,26 +19,44 @@
|
|||
("class" "card lowered w_full no_p_margin")
|
||||
(text "{{ product.description|markdown|safe }}"))
|
||||
|
||||
(text "{% if already_purchased -%}")
|
||||
(span
|
||||
("class" "green flex items_center gap_2")
|
||||
(icon (text "circle-check"))
|
||||
(str (text "economy:label.already_purchased")))
|
||||
(text "{%- endif %}")
|
||||
|
||||
(div
|
||||
("class" "flex gap_2 items_center")
|
||||
(text "{% if user.id != product.owner -%}")
|
||||
(text "{% if not already_purchased -%}")
|
||||
; price
|
||||
(a
|
||||
("class" "button camo lowered")
|
||||
("href" "/wallet")
|
||||
("target" "_blank")
|
||||
(icon (text "badge-cent"))
|
||||
(text "{{ product.price }}"))
|
||||
(text "{% if user.id != product.owner -%}")
|
||||
(text "{% if not already_purchased -%}")
|
||||
; buy button
|
||||
(button
|
||||
("onclick" "purchase()")
|
||||
("disabled" "{{ product.stock == 0 }}")
|
||||
(icon (text "piggy-bank"))
|
||||
(str (text "economy:action.buy")))
|
||||
(text "{% else %}")
|
||||
(span
|
||||
("class" "green flex items_center gap_2")
|
||||
(icon (text "circle-check"))
|
||||
(str (text "economy:label.already_purchased")))
|
||||
; profile style snippets
|
||||
(text "{% if product.method == \"ProfileStyle\" -%} {% if not product.id in applied_configurations_mapped -%}")
|
||||
(button
|
||||
("onclick" "apply()")
|
||||
(icon (text "check"))
|
||||
(str (text "economy:action.apply")))
|
||||
(text "{% else %}")
|
||||
(button
|
||||
("onclick" "remove()")
|
||||
(icon (text "x"))
|
||||
(str (text "economy:action.unapply")))
|
||||
(text "{%- endif %} {%- endif %}")
|
||||
; ...
|
||||
(text "{%- endif %}")
|
||||
(text "{% else %}")
|
||||
(a
|
||||
|
@ -69,6 +87,59 @@
|
|||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (res.ok) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
await trigger(\"atto::debounce\", [\"user::update\"]);
|
||||
fetch(\"/api/v1/auth/user/{{ user.id }}/applied_configuration\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
\"type\": \"StyleSnippet\",
|
||||
\"id\": \"{{ product.id }}\",
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (res.ok) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function remove() {
|
||||
await trigger(\"atto::debounce\", [\"user::update\"]);
|
||||
fetch(\"/api/v1/auth/user/{{ user.id }}/applied_configuration\", {
|
||||
method: \"DELETE\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
\"id\": \"{{ product.id }}\",
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (res.ok) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}"))
|
||||
(text "{% endblock %}")
|
||||
|
|
|
@ -468,6 +468,12 @@
|
|||
("class" "rhs w_full flex flex_col gap_4")
|
||||
(text "{% block content %}{% endblock %}")))))
|
||||
|
||||
(text "{% if not use_user_theme -%}")
|
||||
(text "{% for cnf in applied_configurations -%}")
|
||||
(text "{{ cnf|safe }}")
|
||||
(text "{%- endfor %}")
|
||||
(text "{%- endif %}")
|
||||
|
||||
(text "{% if not is_self and profile.settings.warning -%}")
|
||||
(script
|
||||
(text "setTimeout(() => {
|
||||
|
|
|
@ -1162,6 +1162,26 @@
|
|||
("class" "fade")
|
||||
(text "This represents the site theme shown to users viewing
|
||||
your profile.")))))
|
||||
(text "{% if profile.applied_configurations|length > 0 -%}")
|
||||
(div
|
||||
("class" "card_nest")
|
||||
("ui_ident" "applied_configurations")
|
||||
(div
|
||||
("class" "card small flex items_center gap_2")
|
||||
(icon (text "cog"))
|
||||
(str (text "setttings:label.applied_configurations")))
|
||||
(div
|
||||
("class" "card")
|
||||
(p (text "Products that you have purchased and applied to your profile are displayed below. Snippets are always synced to the product, meaning the owner could update it at any time."))
|
||||
(ul
|
||||
(text "{% for cnf in profile.applied_configurations -%}")
|
||||
(li
|
||||
(text "{{ cnf[0] }} ")
|
||||
(a
|
||||
("href" "/product/{{ cnf[1] }}")
|
||||
(text "{{ cnf[1] }}")))
|
||||
(text "{%- endfor %}"))))
|
||||
(text "{%- endif %}")
|
||||
(button
|
||||
("onclick" "save_settings()")
|
||||
("id" "save_button")
|
||||
|
@ -1742,6 +1762,7 @@
|
|||
\"import_export\",
|
||||
\"theme_preference\",
|
||||
\"profile_theme\",
|
||||
\"applied_configurations\",
|
||||
]);
|
||||
|
||||
ui.generate_settings_ui(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue