diff --git a/crates/app/src/public/html/profile/base.lisp b/crates/app/src/public/html/profile/base.lisp
index 481c007..7962728 100644
--- a/crates/app/src/public/html/profile/base.lisp
+++ b/crates/app/src/public/html/profile/base.lisp
@@ -228,7 +228,7 @@
(icon_class (text "chevron-down") (text "dropdown-arrow"))
(str (text "auth:action.block")))
(div
- ("class" "inner")
+ ("class" "inner left")
(button
("onclick" "toggle_block_user()")
(icon (text "shield"))
diff --git a/crates/app/src/public/html/profile/blocked.lisp b/crates/app/src/public/html/profile/blocked.lisp
index b1c59c1..1a128fa 100644
--- a/crates/app/src/public/html/profile/blocked.lisp
+++ b/crates/app/src/public/html/profile/blocked.lisp
@@ -24,12 +24,24 @@
(div
("class" "card w-full secondary flex gap-2")
(text "{% if user -%} {% if not is_blocking -%}")
- (button
- ("onclick" "toggle_block_user()")
- ("class" "lowered red")
- (text "{{ icon \"shield\" }}")
- (span
- (text "{{ text \"auth:action.block\" }}")))
+ (div
+ ("class" "dropdown")
+ (button
+ ("onclick" "trigger('atto::hooks::dropdown', [event])")
+ ("exclude" "dropdown")
+ ("class" "lowered red")
+ (icon_class (text "chevron-down") (text "dropdown-arrow"))
+ (str (text "auth:action.block")))
+ (div
+ ("class" "inner left")
+ (button
+ ("onclick" "toggle_block_user()")
+ (icon (text "shield"))
+ (str (text "auth:action.block")))
+ (button
+ ("onclick" "ip_block_user()")
+ (icon (text "wifi"))
+ (str (text "auth:action.ip_block")))))
(text "{% else %}")
(button
("onclick" "toggle_block_user()")
@@ -58,6 +70,30 @@
res.message,
]);
});
+ };
+
+ globalThis.ip_block_user = async () => {
+ if (
+ !(await trigger(\"atto::confirm\", [
+ \"Are you sure you would like to do this?\",
+ ]))
+ ) {
+ return;
+ }
+
+ fetch(
+ \"/api/v1/auth/user/{{ profile.id }}/block_ip\",
+ {
+ method: \"POST\",
+ },
+ )
+ .then((res) => res.json())
+ .then((res) => {
+ trigger(\"atto::toast\", [
+ res.ok ? \"success\" : \"error\",
+ res.message,
+ ]);
+ });
};"))
(text "{%- endif %}")
(a