chore:linting,formatting,type fixing, ....
This commit is contained in:
@@ -25,7 +25,17 @@ export default defineConfig(
|
|||||||
rules: {
|
rules: {
|
||||||
// typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
|
// typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
|
||||||
// see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
|
// see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
|
||||||
'no-undef': 'off'
|
'no-undef': 'off',
|
||||||
|
// Disable no-navigation-without-resolve as we're using resolveRoute from $app/paths
|
||||||
|
'svelte/no-navigation-without-resolve': 'off',
|
||||||
|
// Allow unused vars that start with underscore
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
await apiSync.deleteComment(commentId, findId);
|
await apiSync.deleteComment(commentId, findId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function canDeleteComment(comment: any): boolean {
|
function canDeleteComment(comment: { user: { id: string } }): boolean {
|
||||||
return Boolean(
|
return Boolean(
|
||||||
currentUserId && (comment.user.id === currentUserId || comment.user.id === 'current-user')
|
currentUserId && (comment.user.id === currentUserId || comment.user.id === 'current-user')
|
||||||
);
|
);
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
{#snippet loadingSkeleton()}
|
{#snippet loadingSkeleton()}
|
||||||
<div class="loading-skeleton">
|
<div class="loading-skeleton">
|
||||||
{#each Array(3) as _}
|
{#each Array(3) as _, index (index)}
|
||||||
<div class="comment-skeleton">
|
<div class="comment-skeleton">
|
||||||
<Skeleton class="avatar-skeleton" />
|
<Skeleton class="avatar-skeleton" />
|
||||||
<div class="content-skeleton">
|
<div class="content-skeleton">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ProfilePanel } from '$lib';
|
import { ProfilePanel } from '$lib';
|
||||||
|
import { resolveRoute } from '$app/paths';
|
||||||
|
|
||||||
type User = {
|
type User = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
|
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<h1 class="app-title"><a href="/">Serengo</a></h1>
|
<h1 class="app-title"><a href={resolveRoute('/')}>Serengo</a></h1>
|
||||||
<div class="profile-container">
|
<div class="profile-container">
|
||||||
<ProfilePanel
|
<ProfilePanel
|
||||||
username={user.username}
|
username={user.username}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
isLoading: false
|
isLoading: false
|
||||||
});
|
});
|
||||||
|
|
||||||
let apiSync: any = null;
|
let apiSync: typeof import('$lib/stores/api-sync').apiSync | null = null;
|
||||||
|
|
||||||
// Initialize API sync and subscribe to global state
|
// Initialize API sync and subscribe to global state
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
@@ -65,13 +65,15 @@
|
|||||||
|
|
||||||
// Subscribe to global state for this find
|
// Subscribe to global state for this find
|
||||||
const globalLikeState = apiSync.subscribeFindLikes(findId);
|
const globalLikeState = apiSync.subscribeFindLikes(findId);
|
||||||
globalLikeState.subscribe((state: any) => {
|
globalLikeState.subscribe(
|
||||||
likeState.set({
|
(state: { isLiked: boolean; likeCount: number; isLoading: boolean }) => {
|
||||||
isLiked: state.isLiked,
|
likeState.set({
|
||||||
likeCount: state.likeCount,
|
isLiked: state.isLiked,
|
||||||
isLoading: state.isLoading
|
likeCount: state.likeCount,
|
||||||
});
|
isLoading: state.isLoading
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize API sync:', error);
|
console.error('Failed to initialize API sync:', error);
|
||||||
}
|
}
|
||||||
@@ -81,8 +83,7 @@
|
|||||||
async function toggleLike() {
|
async function toggleLike() {
|
||||||
if (!apiSync || !browser) return;
|
if (!apiSync || !browser) return;
|
||||||
|
|
||||||
const currentState = likeState;
|
if ($likeState.isLoading) return;
|
||||||
if (currentState && (currentState as any).isLoading) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiSync.toggleLike(findId);
|
await apiSync.toggleLike(findId);
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
let permissionStatus = $state<NotificationPermission>('default');
|
let permissionStatus = $state<NotificationPermission>('default');
|
||||||
let subscriptionStatus = $state<'idle' | 'subscribing' | 'subscribed' | 'error'>('idle');
|
|
||||||
let errorMessage = $state<string>('');
|
|
||||||
let showPrompt = $state<boolean>(false);
|
let showPrompt = $state<boolean>(false);
|
||||||
let isSupported = $state<boolean>(false);
|
let isSupported = $state<boolean>(false);
|
||||||
|
|
||||||
@@ -57,8 +55,6 @@
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[NotificationManager] Error initializing notifications:', error);
|
console.error('[NotificationManager] Error initializing notifications:', error);
|
||||||
subscriptionStatus = 'error';
|
|
||||||
errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,13 +71,9 @@
|
|||||||
await subscribeToNotifications();
|
await subscribeToNotifications();
|
||||||
} else {
|
} else {
|
||||||
console.log('[NotificationManager] Permission not granted');
|
console.log('[NotificationManager] Permission not granted');
|
||||||
subscriptionStatus = 'error';
|
|
||||||
errorMessage = 'Notification permission was not granted';
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[NotificationManager] Error enabling notifications:', error);
|
console.error('[NotificationManager] Error enabling notifications:', error);
|
||||||
subscriptionStatus = 'error';
|
|
||||||
errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +86,6 @@
|
|||||||
async function subscribeToNotifications() {
|
async function subscribeToNotifications() {
|
||||||
try {
|
try {
|
||||||
console.log('[NotificationManager] subscribeToNotifications called');
|
console.log('[NotificationManager] subscribeToNotifications called');
|
||||||
subscriptionStatus = 'subscribing';
|
|
||||||
|
|
||||||
// Get or register service worker
|
// Get or register service worker
|
||||||
let registration = await navigator.serviceWorker.getRegistration();
|
let registration = await navigator.serviceWorker.getRegistration();
|
||||||
@@ -161,12 +152,9 @@
|
|||||||
throw new Error('Failed to save subscription to server');
|
throw new Error('Failed to save subscription to server');
|
||||||
}
|
}
|
||||||
|
|
||||||
subscriptionStatus = 'subscribed';
|
|
||||||
console.log('[NotificationManager] Successfully subscribed to push notifications!');
|
console.log('[NotificationManager] Successfully subscribed to push notifications!');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[NotificationManager] Error subscribing to push notifications:', error);
|
console.error('[NotificationManager] Error subscribing to push notifications:', error);
|
||||||
subscriptionStatus = 'error';
|
|
||||||
errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,17 +36,16 @@
|
|||||||
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams({
|
const searchParams = new URL('/api/places', window.location.origin).searchParams;
|
||||||
action: 'autocomplete',
|
searchParams.set('action', 'autocomplete');
|
||||||
query: query.trim()
|
searchParams.set('query', query.trim());
|
||||||
});
|
|
||||||
|
|
||||||
if ($coordinates) {
|
if ($coordinates) {
|
||||||
params.set('lat', $coordinates.latitude.toString());
|
searchParams.set('lat', $coordinates.latitude.toString());
|
||||||
params.set('lng', $coordinates.longitude.toString());
|
searchParams.set('lng', $coordinates.longitude.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(`/api/places?${params}`);
|
const response = await fetch(`/api/places?${searchParams}`);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
suggestions = await response.json();
|
suggestions = await response.json();
|
||||||
showSuggestions = true;
|
showSuggestions = true;
|
||||||
@@ -179,7 +178,7 @@
|
|||||||
<div class="suggestion-content">
|
<div class="suggestion-content">
|
||||||
<span class="suggestion-name">{suggestion.description}</span>
|
<span class="suggestion-name">{suggestion.description}</span>
|
||||||
<div class="suggestion-types">
|
<div class="suggestion-types">
|
||||||
{#each suggestion.types.slice(0, 2) as type}
|
{#each suggestion.types.slice(0, 2) as type, index (index)}
|
||||||
<span class="suggestion-type">{type.replace(/_/g, ' ')}</span>
|
<span class="suggestion-type">{type.replace(/_/g, ' ')}</span>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
|
import { resolveRoute } from '$app/paths';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@@ -81,7 +82,7 @@
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
<DropdownMenuItem class="friends-item">
|
<DropdownMenuItem class="friends-item">
|
||||||
<a href="/friends" class="friends-link">Friends</a>
|
<a href={resolveRoute('/friends')} class="friends-link">Friends</a>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
<DropdownMenuItem class="notification-settings-item" onclick={openNotificationSettingsSheet}>
|
<DropdownMenuItem class="notification-settings-item" onclick={openNotificationSettingsSheet}>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { cn, type WithElementRef } from '$lib/utils.js';
|
import { cn, type WithElementRef } from '$lib/utils.js';
|
||||||
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
||||||
import { type VariantProps, tv } from 'tailwind-variants';
|
import { type VariantProps, tv } from 'tailwind-variants';
|
||||||
|
import { resolveRoute } from '$app/paths';
|
||||||
|
|
||||||
export const buttonVariants = tv({
|
export const buttonVariants = tv({
|
||||||
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="button"
|
data-slot="button"
|
||||||
class={cn(buttonVariants({ variant, size }), className)}
|
class={cn(buttonVariants({ variant, size }), className)}
|
||||||
href={disabled ? undefined : href}
|
href={disabled ? undefined : resolveRoute(href)}
|
||||||
aria-disabled={disabled}
|
aria-disabled={disabled}
|
||||||
role={disabled ? 'link' : undefined}
|
role={disabled ? 'link' : undefined}
|
||||||
tabindex={disabled ? -1 : undefined}
|
tabindex={disabled ? -1 : undefined}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { resolveRoute } from '$app/paths';
|
||||||
import { Button } from '$lib/components/button/index.js';
|
import { Button } from '$lib/components/button/index.js';
|
||||||
import * as Card from '$lib/components/card/index.js';
|
import * as Card from '$lib/components/card/index.js';
|
||||||
import { Label } from '$lib/components/label/index.js';
|
import { Label } from '$lib/components/label/index.js';
|
||||||
@@ -62,7 +63,11 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="outline" class="mt-4 w-full" onclick={() => goto('/login/google')}>
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="mt-4 w-full"
|
||||||
|
onclick={() => goto(resolveRoute('/login/google'))}
|
||||||
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
|
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import type { NotificationInsert } from './db/schema';
|
|||||||
import { eq, and, desc } from 'drizzle-orm';
|
import { eq, and, desc } from 'drizzle-orm';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
|
||||||
export type NotificationType = 'friend_request' | 'friend_accepted' | 'find_liked' | 'find_commented';
|
export type NotificationType =
|
||||||
|
| 'friend_request'
|
||||||
|
| 'friend_accepted'
|
||||||
|
| 'find_liked'
|
||||||
|
| 'find_commented';
|
||||||
|
|
||||||
export interface CreateNotificationData {
|
export interface CreateNotificationData {
|
||||||
userId: string;
|
userId: string;
|
||||||
@@ -106,10 +110,7 @@ export class NotificationService {
|
|||||||
*/
|
*/
|
||||||
async markAsRead(notificationIds: string[]): Promise<void> {
|
async markAsRead(notificationIds: string[]): Promise<void> {
|
||||||
for (const id of notificationIds) {
|
for (const id of notificationIds) {
|
||||||
await db
|
await db.update(notification).set({ isRead: true }).where(eq(notification.id, id));
|
||||||
.update(notification)
|
|
||||||
.set({ isRead: true })
|
|
||||||
.where(eq(notification.id, id));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,20 +118,14 @@ export class NotificationService {
|
|||||||
* Mark a single notification as read
|
* Mark a single notification as read
|
||||||
*/
|
*/
|
||||||
async markOneAsRead(notificationId: string): Promise<void> {
|
async markOneAsRead(notificationId: string): Promise<void> {
|
||||||
await db
|
await db.update(notification).set({ isRead: true }).where(eq(notification.id, notificationId));
|
||||||
.update(notification)
|
|
||||||
.set({ isRead: true })
|
|
||||||
.where(eq(notification.id, notificationId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark all notifications as read for a user
|
* Mark all notifications as read for a user
|
||||||
*/
|
*/
|
||||||
async markAllAsRead(userId: string): Promise<void> {
|
async markAllAsRead(userId: string): Promise<void> {
|
||||||
await db
|
await db.update(notification).set({ isRead: true }).where(eq(notification.userId, userId));
|
||||||
.update(notification)
|
|
||||||
.set({ isRead: true })
|
|
||||||
.where(eq(notification.userId, userId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,11 +4,7 @@ import { notificationSubscription } from './db/schema';
|
|||||||
import type { NotificationSubscriptionInsert } from './db/schema';
|
import type { NotificationSubscriptionInsert } from './db/schema';
|
||||||
import { eq, and } from 'drizzle-orm';
|
import { eq, and } from 'drizzle-orm';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import {
|
import { VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT } from '$env/static/private';
|
||||||
VAPID_PUBLIC_KEY,
|
|
||||||
VAPID_PRIVATE_KEY,
|
|
||||||
VAPID_SUBJECT
|
|
||||||
} from '$env/static/private';
|
|
||||||
|
|
||||||
// Initialize web-push with VAPID keys
|
// Initialize web-push with VAPID keys
|
||||||
if (!VAPID_PUBLIC_KEY || !VAPID_PRIVATE_KEY || !VAPID_SUBJECT) {
|
if (!VAPID_PUBLIC_KEY || !VAPID_PRIVATE_KEY || !VAPID_SUBJECT) {
|
||||||
@@ -88,7 +84,10 @@ export class PushService {
|
|||||||
await db
|
await db
|
||||||
.delete(notificationSubscription)
|
.delete(notificationSubscription)
|
||||||
.where(
|
.where(
|
||||||
and(eq(notificationSubscription.userId, userId), eq(notificationSubscription.endpoint, endpoint))
|
and(
|
||||||
|
eq(notificationSubscription.userId, userId),
|
||||||
|
eq(notificationSubscription.endpoint, endpoint)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +99,10 @@ export class PushService {
|
|||||||
.select()
|
.select()
|
||||||
.from(notificationSubscription)
|
.from(notificationSubscription)
|
||||||
.where(
|
.where(
|
||||||
and(eq(notificationSubscription.userId, userId), eq(notificationSubscription.isActive, true))
|
and(
|
||||||
|
eq(notificationSubscription.userId, userId),
|
||||||
|
eq(notificationSubscription.isActive, true)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export const POST: RequestHandler = async ({ params, locals, request }) => {
|
|||||||
const commentId = crypto.randomUUID();
|
const commentId = crypto.randomUUID();
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
const [newComment] = await db
|
await db
|
||||||
.insert(findComment)
|
.insert(findComment)
|
||||||
.values({
|
.values({
|
||||||
id: commentId,
|
id: commentId,
|
||||||
@@ -112,11 +112,14 @@ export const POST: RequestHandler = async ({ params, locals, request }) => {
|
|||||||
|
|
||||||
// Send notification to find owner if not self-comment
|
// Send notification to find owner if not self-comment
|
||||||
const findData = await db.select().from(find).where(eq(find.id, findId)).limit(1);
|
const findData = await db.select().from(find).where(eq(find.id, findId)).limit(1);
|
||||||
|
|
||||||
if (findData.length > 0 && findData[0].userId !== session.userId) {
|
if (findData.length > 0 && findData[0].userId !== session.userId) {
|
||||||
const findOwner = findData[0];
|
const findOwner = findData[0];
|
||||||
const shouldNotify = await notificationService.shouldNotify(findOwner.userId, 'find_commented');
|
const shouldNotify = await notificationService.shouldNotify(
|
||||||
|
findOwner.userId,
|
||||||
|
'find_commented'
|
||||||
|
);
|
||||||
|
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
// Get commenter's username
|
// Get commenter's username
|
||||||
const commenterUser = await db
|
const commenterUser = await db
|
||||||
@@ -124,7 +127,7 @@ export const POST: RequestHandler = async ({ params, locals, request }) => {
|
|||||||
.from(user)
|
.from(user)
|
||||||
.where(eq(user.id, session.userId))
|
.where(eq(user.id, session.userId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
const commenterUsername = commenterUser[0]?.username || 'Someone';
|
const commenterUsername = commenterUser[0]?.username || 'Someone';
|
||||||
const findTitle = findOwner.title || 'your find';
|
const findTitle = findOwner.title || 'your find';
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export async function POST({
|
|||||||
const findOwner = existingFind[0];
|
const findOwner = existingFind[0];
|
||||||
if (findOwner.userId !== locals.user.id) {
|
if (findOwner.userId !== locals.user.id) {
|
||||||
const shouldNotify = await notificationService.shouldNotify(findOwner.userId, 'find_liked');
|
const shouldNotify = await notificationService.shouldNotify(findOwner.userId, 'find_liked');
|
||||||
|
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
// Get liker's username
|
// Get liker's username
|
||||||
const likerUser = await db
|
const likerUser = await db
|
||||||
@@ -73,7 +73,7 @@ export async function POST({
|
|||||||
.from(user)
|
.from(user)
|
||||||
.where(eq(user.id, locals.user.id))
|
.where(eq(user.id, locals.user.id))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
const likerUsername = likerUser[0]?.username || 'Someone';
|
const likerUsername = likerUser[0]?.username || 'Someone';
|
||||||
const findTitle = findOwner.title || 'your find';
|
const findTitle = findOwner.title || 'your find';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { json } from '@sveltejs/kit';
|
import { json } from '@sveltejs/kit';
|
||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
import { findComment, user } from '$lib/server/db/schema';
|
import { findComment } from '$lib/server/db/schema';
|
||||||
import { eq, and } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
export const DELETE: RequestHandler = async ({ params, locals }) => {
|
export const DELETE: RequestHandler = async ({ params, locals }) => {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
|
|||||||
if (action === 'accept') {
|
if (action === 'accept') {
|
||||||
const senderId = friendshipRecord.userId;
|
const senderId = friendshipRecord.userId;
|
||||||
const shouldNotify = await notificationService.shouldNotify(senderId, 'friend_accepted');
|
const shouldNotify = await notificationService.shouldNotify(senderId, 'friend_accepted');
|
||||||
|
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
// Get accepter's username
|
// Get accepter's username
|
||||||
const accepterUser = await db
|
const accepterUser = await db
|
||||||
@@ -86,7 +86,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
|
|||||||
.from(user)
|
.from(user)
|
||||||
.where(eq(user.id, locals.user.id))
|
.where(eq(user.id, locals.user.id))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
const accepterUsername = accepterUser[0]?.username || 'Someone';
|
const accepterUsername = accepterUser[0]?.username || 'Someone';
|
||||||
|
|
||||||
await notificationService.createNotification({
|
await notificationService.createNotification({
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ export const PATCH: RequestHandler = async ({ locals, request }) => {
|
|||||||
} else if (Array.isArray(notificationIds) && notificationIds.length > 0) {
|
} else if (Array.isArray(notificationIds) && notificationIds.length > 0) {
|
||||||
await notificationService.markAsRead(notificationIds);
|
await notificationService.markAsRead(notificationIds);
|
||||||
} else {
|
} else {
|
||||||
return json({ error: 'Invalid request: provide notificationIds or markAll' }, { status: 400 });
|
return json(
|
||||||
|
{ error: 'Invalid request: provide notificationIds or markAll' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return json({ success: true });
|
return json({ success: true });
|
||||||
@@ -66,7 +69,10 @@ export const DELETE: RequestHandler = async ({ locals, request }) => {
|
|||||||
} else if (notificationId) {
|
} else if (notificationId) {
|
||||||
await notificationService.deleteNotification(notificationId, user.id);
|
await notificationService.deleteNotification(notificationId, user.id);
|
||||||
} else {
|
} else {
|
||||||
return json({ error: 'Invalid request: provide notificationId or deleteAll' }, { status: 400 });
|
return json(
|
||||||
|
{ error: 'Invalid request: provide notificationId or deleteAll' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return json({ success: true });
|
return json({ success: true });
|
||||||
|
|||||||
@@ -134,10 +134,10 @@
|
|||||||
// Search users when query changes with debounce
|
// Search users when query changes with debounce
|
||||||
let searchTimeout: ReturnType<typeof setTimeout>;
|
let searchTimeout: ReturnType<typeof setTimeout>;
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
// Track searchQuery dependency explicitly
|
if (searchQuery) {
|
||||||
searchQuery;
|
clearTimeout(searchTimeout);
|
||||||
clearTimeout(searchTimeout);
|
searchTimeout = setTimeout(searchUsers, 300);
|
||||||
searchTimeout = setTimeout(searchUsers, 300);
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user