File size: 3,696 Bytes
9e93b10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<script lang="ts">
	import { getContext } from "svelte";
	import dayjs from "dayjs";
	import calendar from "dayjs/plugin/calendar";
	import { REXPRO_API_BASE_URL } from "$lib/constants";
	import Spinner from "$lib/components/common/Spinner.svelte";
	import Loader from "$lib/components/common/Loader.svelte";

	dayjs.extend(calendar);

	const i18n = getContext("i18n");

	export let chatList: Array<{
		id: string;
		title: string;
		updated_at: number;
		user_id?: string;
		user_name?: string;
		time_range?: string;
	}> | null = null;
	export let loading = false;
	export let allLoaded = false;
	export let showUserInfo = false;
	export let shareUrl = false;
	export let emptyMessage = "No chats found";
	export let onLoadMore: (() => void) | null = null;
	export let onChatClick: ((chatId: string) => void) | null = null;
</script>

<div>
	{#if chatList && chatList.length > 0}
		<div class="flex text-xs font-medium mb-1.5">
			{#if showUserInfo}
				<div class="px-1.5 py-1 w-32">
					{$i18n.t("User")}
				</div>
			{/if}
			<div class="px-1.5 py-1 {showUserInfo ? 'flex-1' : 'basis-3/5'}">
				{$i18n.t("Title")}
			</div>
			<div
				class="px-1.5 py-1 hidden sm:flex {showUserInfo
					? 'w-28'
					: 'basis-2/5'} justify-end"
			>
				{$i18n.t("Updated at")}
			</div>
		</div>
	{/if}
	<div class="max-h-[22rem] overflow-y-scroll">
		{#if loading && (!chatList || chatList.length === 0)}
			<div class="flex justify-center py-8">
				<Spinner />
			</div>
		{:else if !chatList || chatList.length === 0}
			<div class="text-center text-gray-500 text-sm py-8">
				{$i18n.t(emptyMessage)}
			</div>
		{:else}
			{#each chatList as chat, idx (chat.id)}
				{#if chat.time_range && (idx === 0 || chat.time_range !== chatList[idx - 1]?.time_range)}
					<div
						class="w-full text-xs text-gray-500 dark:text-gray-500 font-medium {idx ===
						0
							? ''
							: 'pt-5'} pb-2 px-2"
					>
						{$i18n.t(chat.time_range)}
					</div>
				{/if}

				<div
					class="w-full flex items-center rounded-lg text-sm py-2 px-3 hover:bg-gray-50 dark:hover:bg-gray-850"
				>
					{#if showUserInfo && chat.user_id}
						<div class="w-32 shrink-0 flex items-center gap-2">
							<img
								src="{REXPRO_API_BASE_URL}/users/{chat.user_id}/profile/image"
								alt={chat.user_name || "User"}
								class="size-5 rounded-full object-cover shrink-0"
							/>
							<span
								class="text-xs text-gray-600 dark:text-gray-400 truncate"
								>{chat.user_name || "Unknown"}</span
							>
						</div>
					{/if}
					<a
						class={showUserInfo ? "flex-1" : "basis-3/5"}
						href={shareUrl ? `/s/${chat.id}` : `/c/${chat.id}`}
						on:click={() => onChatClick?.(chat.id)}
					>
						<div class="text-ellipsis line-clamp-1 w-full">
							{chat.title
								.replace(/^\p{Extended_Pictographic}\s*/gu, "")
								.trim()}
						</div>
					</a>

					<div
						class="{showUserInfo
							? 'w-28'
							: 'basis-2/5'} flex items-center justify-end"
					>
						<div
							class="hidden sm:flex text-gray-500 dark:text-gray-400 text-xs"
						>
							{dayjs(chat.updated_at * 1000).calendar(null, {
								sameDay: "[Today] h:mm A",
								lastDay: "[Yesterday] h:mm A",
								lastWeek: "MMM D",
								sameElse: "MMM D, YYYY",
							})}
						</div>
					</div>
				</div>
			{/each}

			{#if !allLoaded && onLoadMore}
				<Loader
					on:visible={() => {
						if (!loading) {
							onLoadMore();
						}
					}}
				>
					<div
						class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2"
					>
						<Spinner className="size-4" />
						<div>{$i18n.t("Loading...")}</div>
					</div>
				</Loader>
			{/if}
		{/if}
	</div>
</div>