Swadhin Biswas Feature/ai code reviewer (#73) · 8/2/2026
105a287
155 lines · 5.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
---
import SettingsLayout from "@/layouts/SettingsLayout.astro";

const user = Astro.locals.user;

if (!user) {
  return Astro.redirect("/login");
}
---

<SettingsLayout title="Account settings">
  <div class="max-w-[640px]">
    <div class="mb-6">
      <h2 class="text-[28px] font-semibold text-foreground">Password and authentication</h2>
      <p class="text-sm text-muted-foreground mt-1">
        Change your password or configure two-factor authentication.
      </p>
    </div>

    <!-- Change Password -->
    <div class="py-5 border-t border-border">
      <h3 class="text-base font-semibold text-foreground mb-4">Change password</h3>
      <form id="password-form" class="space-y-4">
        <div>
          <label for="currentPassword" class="block text-sm font-medium text-foreground mb-1">
            Current password
          </label>
          <input
            type="password"
            name="currentPassword"
            id="currentPassword"
            required
            class="w-full max-w-md rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:border-[#58a6ff] focus:ring-1 focus:ring-[#58a6ff]/30 transition-colors"
          />
        </div>
        <div>
          <label for="newPassword" class="block text-sm font-medium text-foreground mb-1">
            New password
          </label>
          <input
            type="password"
            name="newPassword"
            id="newPassword"
            required
            minlength="8"
            class="w-full max-w-md rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:border-[#58a6ff] focus:ring-1 focus:ring-[#58a6ff]/30 transition-colors"
          />
          <p class="text-xs text-muted-foreground mt-1">At least 8 characters.</p>
        </div>
        <div>
          <label for="confirmPassword" class="block text-sm font-medium text-foreground mb-1">
            Confirm new password
          </label>
          <input
            type="password"
            name="confirmPassword"
            id="confirmPassword"
            required
            minlength="8"
            class="w-full max-w-md rounded-md border border-border bg-background px-3 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:border-[#58a6ff] focus:ring-1 focus:ring-[#58a6ff]/30 transition-colors"
          />
        </div>
        <div class="flex justify-start">
          <button
            type="submit"
            class="px-4 py-1.5 rounded-md bg-[#238636] border border-[#2ea043] text-sm font-medium text-white hover:bg-[#2ea043] transition-colors"
          >
            Update password
          </button>
        </div>
      </form>
    </div>

    <!-- Delete Account -->
    <div class="py-5 border-t border-border">
      <h3 class="text-base font-semibold text-foreground mb-1">Delete account</h3>
      <p class="text-sm text-muted-foreground mb-4">
        Once you delete your account, there is no going back. Please be certain.
      </p>
      <button
        type="button"
        id="delete-account-btn"
        class="px-4 py-1.5 rounded-md border border-[#da3633] bg-transparent text-sm font-medium text-[#da3633] hover:bg-[#da3633]/10 transition-colors"
      >
        Delete account
      </button>
    </div>
  </div>
</SettingsLayout>

<script>
  const passwordForm = document.getElementById("password-form") as HTMLFormElement;
  const deleteBtn = document.getElementById("delete-account-btn");

  passwordForm?.addEventListener("submit", async (e) => {
    e.preventDefault();
    const formData = new FormData(passwordForm);
    const data = Object.fromEntries(formData);

    if (data.newPassword !== data.confirmPassword) {
      alert("New passwords do not match");
      return;
    }

    const submitBtn = passwordForm.querySelector('button[type="submit"]') as HTMLButtonElement;
    const originalText = submitBtn.textContent;
    submitBtn.disabled = true;
    submitBtn.textContent = "Updating...";

    try {
      const response = await fetch("/api/auth/password", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
      });

      if (response.ok) {
        submitBtn.textContent = "Updated!";
        passwordForm.reset();
        setTimeout(() => {
          submitBtn.textContent = originalText;
          submitBtn.disabled = false;
        }, 3000);
      } else {
        const error = await response.json();
        alert(error.message || "Failed to update password");
        submitBtn.textContent = originalText;
        submitBtn.disabled = false;
      }
    } catch (error) {
      console.error("Error updating password:", error);
      alert("An error occurred while updating password");
      submitBtn.textContent = originalText;
      submitBtn.disabled = false;
    }
  });

  deleteBtn?.addEventListener("click", async () => {
    if (confirm("Are you sure you want to delete your account? This action cannot be undone.")) {
      try {
        const response = await fetch("/api/auth/me", { method: "DELETE" });
        if (response.ok) {
          window.location.href = "/";
        } else {
          const error = await response.json();
          alert(error.message || "Failed to delete account");
        }
      } catch (error) {
        console.error("Error deleting account:", error);
        alert("An error occurred while deleting account");
      }
    }
  });
</script>