Add Prettier for TypeScript formatting

- Install prettier
- Configure .prettierrc.json and .prettierignore
- Add npm scripts: format, format:check
- Add Makefile target: format-frontend
- Format all frontend files
This commit is contained in:
counterweight 2025-12-21 21:59:26 +01:00
parent 4b394b0698
commit 37de6f70e0
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
44 changed files with 906 additions and 856 deletions

View file

@ -34,7 +34,8 @@ function validateEmail(value: string): string | undefined {
if (!value) return undefined;
// More comprehensive email regex that matches email-validator behavior
// Checks for: local part, @, domain with at least one dot, valid TLD
const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
const emailRegex =
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
if (!emailRegex.test(value)) {
return "Please enter a valid email address";
}
@ -72,7 +73,7 @@ function validateNostrNpub(value: string): string | undefined {
if (!value.startsWith(npubRules.prefix)) {
return `Nostr npub must start with '${npubRules.prefix}'`;
}
try {
const decoded = bech32.decode(value);
if (decoded.prefix !== "npub") {
@ -186,7 +187,7 @@ export default function ProfilePage() {
const handleInputChange = (field: keyof FormData) => (e: React.ChangeEvent<HTMLInputElement>) => {
let value = e.target.value;
// For telegram: auto-prepend @ if user starts with a valid letter
if (field === "telegram" && value && !value.startsWith("@")) {
// Check if first char is a valid telegram handle start (letter)
@ -194,14 +195,14 @@ export default function ProfilePage() {
value = "@" + value;
}
}
setFormData((prev) => ({ ...prev, [field]: value }));
// Clear any pending validation timeout
if (validationTimeoutRef.current) {
clearTimeout(validationTimeoutRef.current);
}
// Debounce validation - wait 500ms after user stops typing
validationTimeoutRef.current = setTimeout(() => {
const newFormData = { ...formData, [field]: value };
@ -212,11 +213,11 @@ export default function ProfilePage() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validate all fields
const validationErrors = validateForm(formData);
setErrors(validationErrors);
if (Object.keys(validationErrors).length > 0) {
return;
}
@ -300,9 +301,7 @@ export default function ProfilePage() {
style={{ ...styles.input, ...styles.inputReadOnly }}
disabled
/>
<span style={styles.hint}>
This is your login email and cannot be changed here.
</span>
<span style={styles.hint}>This is your login email and cannot be changed here.</span>
</div>
{/* Godfather - shown if user was invited */}
@ -315,9 +314,7 @@ export default function ProfilePage() {
<div style={styles.godfatherBox}>
<span style={styles.godfatherEmail}>{godfatherEmail}</span>
</div>
<span style={styles.hint}>
The user who invited you to join.
</span>
<span style={styles.hint}>The user who invited you to join.</span>
</div>
)}
@ -344,9 +341,7 @@ export default function ProfilePage() {
}}
placeholder="alternate@example.com"
/>
{errors.contact_email && (
<span style={styles.errorText}>{errors.contact_email}</span>
)}
{errors.contact_email && <span style={styles.errorText}>{errors.contact_email}</span>}
</div>
{/* Telegram */}
@ -365,9 +360,7 @@ export default function ProfilePage() {
}}
placeholder="@username"
/>
{errors.telegram && (
<span style={styles.errorText}>{errors.telegram}</span>
)}
{errors.telegram && <span style={styles.errorText}>{errors.telegram}</span>}
</div>
{/* Signal */}
@ -386,9 +379,7 @@ export default function ProfilePage() {
}}
placeholder="username.01"
/>
{errors.signal && (
<span style={styles.errorText}>{errors.signal}</span>
)}
{errors.signal && <span style={styles.errorText}>{errors.signal}</span>}
</div>
{/* Nostr npub */}
@ -407,9 +398,7 @@ export default function ProfilePage() {
}}
placeholder="npub1..."
/>
{errors.nostr_npub && (
<span style={styles.errorText}>{errors.nostr_npub}</span>
)}
{errors.nostr_npub && <span style={styles.errorText}>{errors.nostr_npub}</span>}
</div>
<button