(text "{% extends \"root.html\" %} {% block head %}") (title (text "{{ product.title }} - {{ config.name }}")) (text "{% endblock %} {% block body %} {{ macros::nav(selected=\"\") }}") (main ("class" "flex flex_col gap_2") (text "{{ components::post_media(upload_ids=product.uploads.thumbnails) }}") (div ("class" "card flex flex_col gap_2") (h3 ("style" "height: 32px") (text "{{ product.title }}")) (text "{{ components::full_username(user=owner) }}") (text "{% if product.stock >= 0 -%}") (span ("class" "red") (text "{{ product.stock }} remaining")) (text "{%- endif %}") (div ("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 }}")) ; buy button (button ("onclick" "purchase()") ("disabled" "{{ product.stock == 0 }}") (icon (text "piggy-bank")) (str (text "economy:action.buy"))) (text "{% else %}") ; 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 ("class" "button") ("href" "/product/{{ product.id }}/edit") (icon (text "settings")) (str (text "general:label.edit"))) (text "{%- endif %}")))) (script (text "async function purchase() { await trigger(\"atto::debounce\", [\"products::buy\"]); if ( !(await trigger(\"atto::confirm\", [ \"Are you sure you would like to do this? Your new balance will be {{ user.coins - product.price }} coins.\", ])) ) { return; } fetch(\"/api/v1/products/{{ product.id }}/buy\", { method: \"POST\", }) .then((res) => res.json()) .then((res) => { trigger(\"atto::toast\", [ 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 %}")