ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
1import { Upload, Sparkles, ChevronRight, Database } from "lucide-react";
2import { ATPROTO_APPS } from "../config/atprotoApps";
3import type { Upload as UploadType } from "../types";
4import FaviconIcon from "../components/FaviconIcon";
5import type { UserSettings } from "../types/settings";
6import { UploadHistorySkeleton } from "./common/LoadingSkeleton";
7import { getPlatformColor } from "../lib/utils/platform";
8import { formatRelativeTime } from "../lib/utils/date";
9import EmptyState from "./common/EmptyState";
10import SetupPrompt from "./common/SetupPrompt";
11import Card from "./common/Card";
12import Badge from "./common/Badge";
13import CardItem from "./common/CardItem";
14
15interface HistoryTabProps {
16 uploads: UploadType[];
17 wizardCompleted: boolean;
18 onShowWizard: () => void;
19 isLoading: boolean;
20 userSettings: UserSettings;
21 onLoadUpload: (uploadId: string) => void;
22}
23
24export default function HistoryTab({
25 uploads,
26 wizardCompleted,
27 onShowWizard,
28 isLoading,
29 userSettings,
30 onLoadUpload,
31}: HistoryTabProps) {
32 return (
33 <div className="p-6">
34 {/* Setup Assistant Banner - Only show if wizard not completed */}
35 {!wizardCompleted && (
36 <SetupPrompt
37 variant="banner"
38 isCompleted={wizardCompleted}
39 onShowWizard={onShowWizard}
40 />
41 )}
42
43 <div className="flex items-center space-x-3 mb-4">
44 <div>
45 <h2 className="text-xl font-bold text-purple-950 dark:text-cyan-50">
46 Previously Uploaded
47 </h2>
48 <p className="text-sm text-purple-750 dark:text-cyan-250">
49 Reconnect with your light trail
50 </p>
51 </div>
52 </div>
53
54 {/* Data Storage Disabled Notice */}
55 {!userSettings.saveData && (
56 <Card className="mb-4 p-4 border-orange-650/50 dark:border-amber-400/50 bg-purple-100/50 dark:bg-slate-900/50">
57 <div className="flex items-start space-x-3">
58 <Database className="w-5 h-5 text-orange-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
59 <div>
60 <h3 className="font-semibold text-purple-950 dark:text-cyan-50 mb-1">
61 Data Storage Disabled
62 </h3>
63 <p className="text-sm text-purple-900 dark:text-cyan-100">
64 You've disabled data storage in your settings. Enable "Save my
65 data" in the Settings tab to save your upload history.
66 </p>
67 </div>
68 </div>
69 </Card>
70 )}
71
72 {isLoading ? (
73 <div className="space-y-3">
74 {[...Array(3)].map((_, i) => (
75 <UploadHistorySkeleton key={i} />
76 ))}
77 </div>
78 ) : uploads.length === 0 ? (
79 <EmptyState
80 icon={Upload}
81 title="No previous uploads yet"
82 message="Upload your first file to get started"
83 />
84 ) : (
85 <div className="space-y-3">
86 {uploads.map((upload) => {
87 const destApp =
88 ATPROTO_APPS[
89 userSettings.platformDestinations[
90 upload.sourcePlatform as keyof typeof userSettings.platformDestinations
91 ]
92 ];
93 return (
94 <Card
95 key={upload.uploadId}
96 variant="upload"
97 className="w-full"
98 >
99 <CardItem
100 padding="p-4"
101 badgeIndentClass="sm:pl-[56px]"
102 onClick={() => onLoadUpload(upload.uploadId)}
103 avatar={
104 <div
105 className={`w-10 h-10 bg-gradient-to-r ${getPlatformColor(upload.sourcePlatform)} rounded-xl flex items-center justify-center flex-shrink-0 shadow-md`}
106 >
107 <Sparkles className="w-6 h-6 text-white" />
108 </div>
109 }
110 content={
111 <>
112 <div className="flex flex-wrap items-start justify-between gap-x-4 gap-y-2">
113 <div className="font-semibold text-purple-950 dark:text-cyan-50 capitalize leading-tight">
114 {upload.sourcePlatform}
115 </div>
116 <div className="flex items-center gap-2 flex-shrink-0">
117 <span className="text-sm text-purple-750 dark:text-cyan-250 whitespace-nowrap flex-shrink-0">
118 {upload.matchedUsers}{" "}
119 {upload.matchedUsers === 1 ? "match" : "matches"}
120 </span>
121 </div>
122 </div>
123 {destApp && (
124 <a
125 href={destApp.link}
126 target="_blank"
127 rel="noopener noreferrer"
128 onClick={(e) => e.stopPropagation()}
129 className="text-sm text-purple-750 dark:text-cyan-250 hover:underline leading-tight flex items-center space-x-1 w-fit"
130 >
131 <span>{destApp.action} on</span>
132
133 <FaviconIcon
134 url={destApp.icon}
135 alt={destApp.name}
136 className="w-3 h-3 mb-0.5 flex-shrink-0"
137 />
138
139 <span>{destApp.name}</span>
140 </a>
141 )}
142 </>
143 }
144 badges={
145 <>
146 <Badge variant="info">
147 {upload.totalUsers}{" "}
148 {upload.totalUsers === 1 ? "user found" : "users found"}
149 </Badge>
150 <Badge variant="info">
151 Uploaded {formatRelativeTime(upload.createdAt)}
152 </Badge>
153 </>
154 }
155 />
156 </Card>
157 );
158 })}
159 </div>
160 )}
161 </div>
162 );
163}