refactor: improve code formatting and readability in page.tsx

This commit is contained in:
Abhimanyu Saharan
2026-02-13 21:30:29 +05:30
parent 277bfcb33a
commit aea69f5118
3 changed files with 96 additions and 44 deletions

View File

@@ -580,17 +580,15 @@ const formatCustomFieldDetailValue = (
const trimmed = value.trim(); const trimmed = value.trim();
if (!trimmed) return "—"; if (!trimmed) return "—";
try { try {
// Validate URL before rendering as a link. const parsedUrl = new URL(trimmed);
// eslint-disable-next-line no-new
new URL(trimmed);
return ( return (
<a <a
href={trimmed} href={parsedUrl.toString()}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="inline-flex items-center gap-1 text-blue-700 underline decoration-blue-300 underline-offset-2 hover:text-blue-800" className="inline-flex items-center gap-1 text-blue-700 underline decoration-blue-300 underline-offset-2 hover:text-blue-800"
> >
<span className="break-all">{trimmed}</span> <span className="break-all">{parsedUrl.toString()}</span>
<ArrowUpRight className="h-3.5 w-3.5 flex-shrink-0" /> <ArrowUpRight className="h-3.5 w-3.5 flex-shrink-0" />
</a> </a>
); );
@@ -601,8 +599,7 @@ const formatCustomFieldDetailValue = (
if (fieldType === "json") { if (fieldType === "json") {
try { try {
const normalized = const normalized = typeof value === "string" ? JSON.parse(value) : value;
typeof value === "string" ? JSON.parse(value) : value;
return ( return (
<pre className="whitespace-pre-wrap break-words rounded border border-slate-200 bg-white px-2 py-1 font-mono text-xs leading-relaxed text-slate-800"> <pre className="whitespace-pre-wrap break-words rounded border border-slate-200 bg-white px-2 py-1 font-mono text-xs leading-relaxed text-slate-800">
{JSON.stringify(normalized, null, 2)} {JSON.stringify(normalized, null, 2)}
@@ -615,7 +612,11 @@ const formatCustomFieldDetailValue = (
if (fieldType === "text_long") { if (fieldType === "text_long") {
const text = customFieldInputText(value); const text = customFieldInputText(value);
return text ? <span className="whitespace-pre-wrap break-words">{text}</span> : "—"; return text ? (
<span className="whitespace-pre-wrap break-words">{text}</span>
) : (
"—"
);
} }
return customFieldInputText(value) || "—"; return customFieldInputText(value) || "—";
@@ -634,7 +635,8 @@ const isCustomFieldVisible = (
value: unknown, value: unknown,
): boolean => { ): boolean => {
if (definition.ui_visibility === "hidden") return false; if (definition.ui_visibility === "hidden") return false;
if (definition.ui_visibility === "if_set") return isCustomFieldValueSet(value); if (definition.ui_visibility === "if_set")
return isCustomFieldValueSet(value);
return true; return true;
}; };
@@ -644,7 +646,10 @@ const parseCustomFieldInputValue = (
): unknown | null => { ): unknown | null => {
const trimmed = text.trim(); const trimmed = text.trim();
if (!trimmed) return null; if (!trimmed) return null;
if (definition.field_type === "text" || definition.field_type === "text_long") { if (
definition.field_type === "text" ||
definition.field_type === "text_long"
) {
return trimmed; return trimmed;
} }
if (definition.field_type === "integer") { if (definition.field_type === "integer") {
@@ -739,7 +744,10 @@ const customFieldPatchPayload = (
): TaskCustomFieldValues => ): TaskCustomFieldValues =>
definitions.reduce((acc, definition) => { definitions.reduce((acc, definition) => {
const key = definition.field_key; const key = definition.field_key;
const currentValue = Object.prototype.hasOwnProperty.call(currentValues, key) const currentValue = Object.prototype.hasOwnProperty.call(
currentValues,
key,
)
? currentValues[key] ? currentValues[key]
: null; : null;
const nextValue = Object.prototype.hasOwnProperty.call(nextValues, key) const nextValue = Object.prototype.hasOwnProperty.call(nextValues, key)
@@ -2855,7 +2863,10 @@ export default function BoardDetailPage() {
if (dueDateChanged) { if (dueDateChanged) {
updatePayload.due_at = localDateInputToUtcIso(editDueDate); updatePayload.due_at = localDateInputToUtcIso(editDueDate);
} }
if (customFieldValuesChanged && Object.keys(editCustomFieldPatch).length > 0) { if (
customFieldValuesChanged &&
Object.keys(editCustomFieldPatch).length > 0
) {
updatePayload.custom_field_values = editCustomFieldPatch; updatePayload.custom_field_values = editCustomFieldPatch;
} }
@@ -4343,7 +4354,8 @@ export default function BoardDetailPage() {
) : ( ) : (
<div className="space-y-3"> <div className="space-y-3">
{boardCustomFieldDefinitions.map((definition) => { {boardCustomFieldDefinitions.map((definition) => {
const fieldValue = editCustomFieldValues[definition.field_key]; const fieldValue =
editCustomFieldValues[definition.field_key];
if (!isCustomFieldVisible(definition, fieldValue)) { if (!isCustomFieldVisible(definition, fieldValue)) {
return null; return null;
} }
@@ -4371,7 +4383,9 @@ export default function BoardDetailPage() {
value === "unset" ? null : value === "true", value === "unset" ? null : value === "true",
})) }))
} }
disabled={!selectedTask || isSavingTask || !canWrite} disabled={
!selectedTask || isSavingTask || !canWrite
}
> >
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Optional" /> <SelectValue placeholder="Optional" />
@@ -4389,7 +4403,8 @@ export default function BoardDetailPage() {
onChange={(event) => onChange={(event) =>
setEditCustomFieldValues((prev) => ({ setEditCustomFieldValues((prev) => ({
...prev, ...prev,
[definition.field_key]: parseCustomFieldInputValue( [definition.field_key]:
parseCustomFieldInputValue(
definition, definition,
event.target.value, event.target.value,
), ),
@@ -4402,7 +4417,9 @@ export default function BoardDetailPage() {
: "Optional" : "Optional"
} }
rows={definition.field_type === "text_long" ? 3 : 4} rows={definition.field_type === "text_long" ? 3 : 4}
disabled={!selectedTask || isSavingTask || !canWrite} disabled={
!selectedTask || isSavingTask || !canWrite
}
/> />
) : ( ) : (
<Input <Input
@@ -4418,12 +4435,17 @@ export default function BoardDetailPage() {
? "url" ? "url"
: "text" : "text"
} }
step={definition.field_type === "decimal" ? "any" : undefined} step={
definition.field_type === "decimal"
? "any"
: undefined
}
value={customFieldInputText(fieldValue)} value={customFieldInputText(fieldValue)}
onChange={(event) => onChange={(event) =>
setEditCustomFieldValues((prev) => ({ setEditCustomFieldValues((prev) => ({
...prev, ...prev,
[definition.field_key]: parseCustomFieldInputValue( [definition.field_key]:
parseCustomFieldInputValue(
definition, definition,
event.target.value, event.target.value,
), ),
@@ -4435,7 +4457,9 @@ export default function BoardDetailPage() {
? `Default: ${customFieldInputText(definition.default_value)}` ? `Default: ${customFieldInputText(definition.default_value)}`
: "Optional" : "Optional"
} }
disabled={!selectedTask || isSavingTask || !canWrite} disabled={
!selectedTask || isSavingTask || !canWrite
}
/> />
)} )}
{definition.description ? ( {definition.description ? (
@@ -4833,7 +4857,8 @@ export default function BoardDetailPage() {
onChange={(event) => onChange={(event) =>
setCreateCustomFieldValues((prev) => ({ setCreateCustomFieldValues((prev) => ({
...prev, ...prev,
[definition.field_key]: parseCustomFieldInputValue( [definition.field_key]:
parseCustomFieldInputValue(
definition, definition,
event.target.value, event.target.value,
), ),
@@ -4862,12 +4887,17 @@ export default function BoardDetailPage() {
? "url" ? "url"
: "text" : "text"
} }
step={definition.field_type === "decimal" ? "any" : undefined} step={
definition.field_type === "decimal"
? "any"
: undefined
}
value={customFieldInputText(fieldValue)} value={customFieldInputText(fieldValue)}
onChange={(event) => onChange={(event) =>
setCreateCustomFieldValues((prev) => ({ setCreateCustomFieldValues((prev) => ({
...prev, ...prev,
[definition.field_key]: parseCustomFieldInputValue( [definition.field_key]:
parseCustomFieldInputValue(
definition, definition,
event.target.value, event.target.value,
), ),

View File

@@ -67,7 +67,13 @@ type EditCustomFieldFormProps = {
onSubmit: (updates: TaskCustomFieldDefinitionUpdate) => Promise<void>; onSubmit: (updates: TaskCustomFieldDefinitionUpdate) => Promise<void>;
}; };
const STRING_FIELD_TYPES = new Set(["text", "text_long", "date", "date_time", "url"]); const STRING_FIELD_TYPES = new Set([
"text",
"text_long",
"date",
"date_time",
"url",
]);
const parseDefaultValue = ( const parseDefaultValue = (
fieldType: FormState["fieldType"], fieldType: FormState["fieldType"],
@@ -92,11 +98,14 @@ const parseDefaultValue = (
} }
if (fieldType === "boolean") { if (fieldType === "boolean") {
if (trimmed.toLowerCase() === "true") return { value: true, error: null }; if (trimmed.toLowerCase() === "true") return { value: true, error: null };
if (trimmed.toLowerCase() === "false") if (trimmed.toLowerCase() === "false") return { value: false, error: null };
return { value: false, error: null };
return { value: null, error: "Default value must be true or false." }; return { value: null, error: "Default value must be true or false." };
} }
if (fieldType === "date" || fieldType === "date_time" || fieldType === "url") { if (
fieldType === "date" ||
fieldType === "date_time" ||
fieldType === "url"
) {
return { value: trimmed, error: null }; return { value: trimmed, error: null };
} }
if (fieldType === "json") { if (fieldType === "json") {
@@ -198,7 +207,9 @@ function EditCustomFieldForm({
trimmedValidationRegex && trimmedValidationRegex &&
!STRING_FIELD_TYPES.has(formState.fieldType) !STRING_FIELD_TYPES.has(formState.fieldType)
) { ) {
setSaveError("Validation regex is only supported for string field types."); setSaveError(
"Validation regex is only supported for string field types.",
);
return; return;
} }
const parsedDefaultValue = parseDefaultValue( const parsedDefaultValue = parseDefaultValue(
@@ -455,7 +466,9 @@ function EditCustomFieldForm({
Loading boards Loading boards
</div> </div>
) : boardsError ? ( ) : boardsError ? (
<div className="px-4 py-6 text-sm text-rose-700">{boardsError}</div> <div className="px-4 py-6 text-sm text-rose-700">
{boardsError}
</div>
) : filteredBoards.length === 0 ? ( ) : filteredBoards.length === 0 ? (
<div className="px-4 py-6 text-sm text-slate-500"> <div className="px-4 py-6 text-sm text-slate-500">
No boards found. No boards found.

View File

@@ -63,7 +63,13 @@ const defaultFormState: FormState = {
defaultValue: "", defaultValue: "",
}; };
const STRING_FIELD_TYPES = new Set(["text", "text_long", "date", "date_time", "url"]); const STRING_FIELD_TYPES = new Set([
"text",
"text_long",
"date",
"date_time",
"url",
]);
const parseDefaultValue = ( const parseDefaultValue = (
fieldType: FormState["fieldType"], fieldType: FormState["fieldType"],
@@ -88,11 +94,14 @@ const parseDefaultValue = (
} }
if (fieldType === "boolean") { if (fieldType === "boolean") {
if (trimmed.toLowerCase() === "true") return { value: true, error: null }; if (trimmed.toLowerCase() === "true") return { value: true, error: null };
if (trimmed.toLowerCase() === "false") if (trimmed.toLowerCase() === "false") return { value: false, error: null };
return { value: false, error: null };
return { value: null, error: "Default value must be true or false." }; return { value: null, error: "Default value must be true or false." };
} }
if (fieldType === "date" || fieldType === "date_time" || fieldType === "url") { if (
fieldType === "date" ||
fieldType === "date_time" ||
fieldType === "url"
) {
return { value: trimmed, error: null }; return { value: trimmed, error: null };
} }
if (fieldType === "json") { if (fieldType === "json") {