Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions frontend/src/lib/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ export class ApiClient {
});
}

async put<T>(endpoint: string, data?: unknown): Promise<T> {
return this.request<T>(endpoint, {
method: "PUT",
body: data ? JSON.stringify(data) : undefined
});
}

async delete<T>(endpoint: string, data?: unknown): Promise<T> {
return this.request<T>(endpoint, {
method: "DELETE",
Expand Down
15 changes: 11 additions & 4 deletions frontend/src/lib/api/links.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { apiClient } from "./client";
import { fetchUrlTitle } from "./metadata";
import type {
Link,
CreateLinkRequest,
Expand Down Expand Up @@ -90,10 +91,7 @@ export const linksApi = {
* @throws ApiError if link not found (404) or validation fails (400)
*/
async update(id: string, data: UpdateLinkRequest): Promise<Link> {
return apiClient.request<Link>(`/api/links/${id}`, {
method: "PUT",
body: JSON.stringify(data)
});
return apiClient.put<Link>(`/api/links/${id}`, data);
},

/**
Expand Down Expand Up @@ -138,6 +136,15 @@ export const linksApi = {

async importBatch(links: ImportLinkRow[]): Promise<ImportBatchResult> {
return apiClient.post<ImportBatchResult>("/api/links/import", { links });
},

/**
* Fetch the title of a destination URL
* @param url - The URL to fetch the title from
* @returns Page title or null if unable to fetch
*/
async fetchUrlTitle(url: string): Promise<string | null> {
return fetchUrlTitle(url);
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { apiClient } from "$lib/api/client";
import { apiClient } from "./client";

interface FetchTitleResponse {
title: string | null;
Expand Down Expand Up @@ -32,22 +32,3 @@ export async function fetchUrlTitle(url: string): Promise<string | null> {
return null;
}
}

/**
* Debounce function to limit how often a function is called
* @param func - The function to debounce
* @param delay - Delay in milliseconds
* @returns Debounced function
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function debounce<T extends (...args: any[]) => any>(
func: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout>;

return (...args: Parameters<T>) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
}
4 changes: 2 additions & 2 deletions frontend/src/lib/components/LinkModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
UsageResponse,
UtmParams
} from "$lib/types/api";
import { debounce, fetchUrlTitle } from "$lib/utils/url-title";
import { debounce } from "$lib/utils/helpers";
import { createEventDispatcher, onMount } from "svelte";

interface Props {
Expand Down Expand Up @@ -295,7 +295,7 @@
isFetchingTitle = true;

try {
const fetchedTitle = await fetchUrlTitle(url.trim());
const fetchedTitle = await linksApi.fetchUrlTitle(url.trim());
// Only set the title if user hasn't entered one and we got a valid title
if (!hasUserEnteredTitle && fetchedTitle) {
title = fetchedTitle;
Expand Down
6 changes: 0 additions & 6 deletions frontend/src/lib/stores/auth.ts

This file was deleted.

7 changes: 0 additions & 7 deletions frontend/src/lib/stores/links.ts

This file was deleted.

19 changes: 19 additions & 0 deletions frontend/src/lib/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any

/**
* Debounce function to limit how often a function is called
* @param func - The function to debounce
* @param delay - Delay in milliseconds
* @returns Debounced function
*/
export function debounce<T extends (...args: any[]) => any>(
func: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout>;

return (...args: Parameters<T>) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
}
Loading