Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion platforms/dreamSync/client/src/pages/wishlist-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default function WishlistEditor() {
<Sparkles className="w-8 h-8 text-blue-400" />
</div>
<p className="text-lg text-gray-300">
Welcome back, <span className="font-semibold text-white">{user?.firstName || user?.email || 'User'}</span>!
Welcome back, <span className="font-semibold text-white">{user?.name|| user?.email || 'User'}</span>!
</p>
<p className="text-sm text-gray-400 mt-2">
{existingWishlist ? 'Edit your wishlist' : 'Create and share your dreams, goals, and what you can offer to the world'}
Expand Down
1 change: 1 addition & 0 deletions platforms/dreamSync/shared/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ export type GroupSuggestion = Suggestion;

// Extended types for API responses
export type UserWithProfile = User & {
name?:string;
profile?: Profile;
skills?: Skill[];
interests?: Interest[];
Expand Down
45 changes: 43 additions & 2 deletions platforms/pictique/src/lib/fragments/Profile/Profile.svelte
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
<script lang="ts">
import type { PostData, userProfile } from '$lib/types';
import { Button } from '$lib/ui';
import { HugeiconsIcon } from '@hugeicons/svelte';
import Post from '../Post/Post.svelte';
import { Spring } from 'svelte/motion';
import { Tick01Icon } from '@hugeicons/core-free-icons';

let {
variant = 'user',
profileData,
handleFollow,
handleSinglePost,
handleMessage
handleMessage,
isFollowing = $bindable(false),
didFollowed = $bindable(false)
}: {
variant: 'user' | 'other';
profileData: userProfile;
handleSinglePost: (post: PostData) => void;
handleFollow: () => Promise<void>;
handleMessage: () => Promise<void>;
isFollowing: boolean;
didFollowed: boolean;
} = $props();

let imgPosts = $derived(profileData.posts.filter((e) => e.imgUris && e.imgUris.length > 0));

const btnScale = new Spring(1, { stiffness: 0.2, damping: 0.4 });

async function wrappedFollow() {
btnScale.target = 0.95;
await handleFollow();
btnScale.target = 1;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</script>

<div class="flex flex-col gap-4 p-4">
Expand All @@ -36,7 +51,33 @@
</div>
{#if variant === 'other'}
<div class="flex gap-2">
<Button variant="primary" size="sm" callback={handleFollow}>Follow</Button>
<div style="transform: scale({btnScale.current}); transition: transform 0.2s ease;">
<Button
variant={'primary'}
size="sm"
callback={wrappedFollow}
disabled={isFollowing || didFollowed}
class="min-w-[110px] transition-all duration-500 {didFollowed
? 'opacity-80'
: ''}"
>
<div class="flex items-center justify-center gap-2">
{#if didFollowed}
<HugeiconsIcon icon={Tick01Icon} size={16} />
<span>Followed</span>
{:else if isFollowing}
<span class="flex gap-0.5">
<span class="animate-bounce">.</span>
<span class="animate-bounce [animation-delay:0.2s]">.</span>
<span class="animate-bounce [animation-delay:0.4s]">.</span>
</span>
<span>Following</span>
{:else}
Follow
{/if}
</div>
</Button>
</div>
<Button variant="primary" size="sm" callback={handleMessage}>Message</Button>
</div>
{/if}
Expand Down
21 changes: 20 additions & 1 deletion platforms/pictique/src/routes/(auth)/auth/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
let qrData = $state<string>('');
let isMobile = $state(false);
let errorMessage = $state<string | null>(null);
let countdown = $state(60);
let timerInterval: ReturnType<typeof setInterval>;

function checkMobile() {
isMobile = window.innerWidth <= 640; // Tailwind's `sm` breakpoint
Expand Down Expand Up @@ -69,6 +71,17 @@
}
}

function startTimer() {
timerInterval = setInterval(() => {
if (countdown > 0) {
countdown -= 1;
} else {
clearInterval(timerInterval);
window.location.reload();
}
}, 1000);
}

onMount(async () => {
checkMobile();
window.addEventListener('resize', checkMobile);
Expand All @@ -93,6 +106,8 @@
const { data } = await apiClient.get('/api/auth/offer');
qrData = data.uri;

startTimer();

function watchEventStream(id: string) {
const sseUrl = new URL(`/api/auth/sessions/${id}`, PUBLIC_PICTIQUE_BASE_URL).toString();
const eventSource = new EventSource(sseUrl);
Expand Down Expand Up @@ -133,6 +148,7 @@
watchEventStream(new URL(qrData).searchParams.get('session') as string);

onDestroy(() => {
if (timerInterval) clearInterval(timerInterval);
window.removeEventListener('resize', checkMobile);
Comment thread
grv-saini-20 marked this conversation as resolved.
});
});
Expand Down Expand Up @@ -209,7 +225,10 @@

<p class="text-center">
<span class="mb-1 block font-bold text-gray-600"
>The {isMobileDevice() ? 'button' : 'code'} is valid for 60 seconds</span
>The {isMobileDevice() ? 'button' : 'QR code'} is valid for
<span class={countdown <= 10 ? 'animate-pulse text-red-500' : 'text-orange-600'}>
{countdown}s
</span></span
>
<span class="block font-light text-gray-600">Please refresh the page if it expires</span
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
let error = $state<string | null>(null);
let loading = $state(true);
let ownerId: string | null = $derived(getAuthId());
let isFollowing = $state(false);
let didFollowed = $state(false);
let ownerProfile = $derived.by(async () => {
if (ownerId) {
const response = await apiClient.get<userProfile>(`/api/users/${ownerId}`);
Expand All @@ -50,10 +52,17 @@

async function handleFollow() {
try {
await apiClient.post(`/api/users/${profileId}/follow`);
await fetchProfile(); // Refresh profile to update follower count
isFollowing = true;
const response = await apiClient.post(`/api/users/${profileId}/follow`);
if (response) {
didFollowed = true;
// await fetchProfile();
}
} catch (err) {
error = err instanceof Error ? err.message : 'Failed to follow user';
didFollowed = false;
} finally {
isFollowing = false;
}
}

Expand Down Expand Up @@ -94,6 +103,8 @@
</div>
{:else if profile}
<Profile
bind:isFollowing
bind:didFollowed
variant={ownerId === profileId ? 'user' : 'other'}
profileData={profile}
handleSinglePost={(post) => handlePostClick(post)}
Expand Down