build view count
This commit is contained in:
@@ -70,6 +70,10 @@ if (!memesCols.find((c) => c.name === 'share_count')) {
|
|||||||
db.exec('ALTER TABLE memes ADD COLUMN share_count INTEGER NOT NULL DEFAULT 0');
|
db.exec('ALTER TABLE memes ADD COLUMN share_count INTEGER NOT NULL DEFAULT 0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!memesCols.find((c) => c.name === 'view_count')) {
|
||||||
|
db.exec('ALTER TABLE memes ADD COLUMN view_count INTEGER NOT NULL DEFAULT 0');
|
||||||
|
}
|
||||||
|
|
||||||
// Indexes that depend on migrated columns — created after columns are guaranteed to exist
|
// Indexes that depend on migrated columns — created after columns are guaranteed to exist
|
||||||
db.exec(`
|
db.exec(`
|
||||||
CREATE INDEX IF NOT EXISTS idx_memes_collection_id ON memes(collection_id);
|
CREATE INDEX IF NOT EXISTS idx_memes_collection_id ON memes(collection_id);
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ export async function shareRoutes(app: FastifyInstance) {
|
|||||||
return reply.status(404).send('Not found');
|
return reply.status(404).send('Not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Count every visit to the share page as a link click
|
||||||
|
db.prepare('UPDATE memes SET view_count = view_count + 1 WHERE id = ?').run(meme.id);
|
||||||
|
|
||||||
const base = getBaseUrl(req as any);
|
const base = getBaseUrl(req as any);
|
||||||
const pageUrl = `${base}/m/${meme.id}`;
|
const pageUrl = `${base}/m/${meme.id}`;
|
||||||
const imageUrl = `${base}/images/${meme.file_path}`;
|
const imageUrl = `${base}/images/${meme.file_path}`;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export interface Meme {
|
|||||||
collection_id: number | null;
|
collection_id: number | null;
|
||||||
ocr_text: string | null;
|
ocr_text: string | null;
|
||||||
share_count: number;
|
share_count: number;
|
||||||
|
view_count: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export interface Meme {
|
|||||||
collection_id: number | null;
|
collection_id: number | null;
|
||||||
ocr_text: string | null;
|
ocr_text: string | null;
|
||||||
share_count: number;
|
share_count: number;
|
||||||
|
view_count: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
children?: Meme[];
|
children?: Meme[];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { X, Minimize2, Trash2, Edit2, Check, Layers, FolderOpen, Inbox, ScanText, ChevronDown, ChevronUp, ExternalLink, Image, Info, Share2 } from 'lucide-react';
|
import { X, Minimize2, Trash2, Edit2, Check, Layers, FolderOpen, Inbox, ScanText, ChevronDown, ChevronUp, ExternalLink, Image, Info, Share2, MousePointerClick } from 'lucide-react';
|
||||||
import { useMeme, useDeleteMeme, useUpdateMeme, useMoveMeme, useCollections } from '../hooks/useMemes';
|
import { useMeme, useDeleteMeme, useUpdateMeme, useMoveMeme, useCollections } from '../hooks/useMemes';
|
||||||
import { useAuth } from '../hooks/useAuth';
|
import { useAuth } from '../hooks/useAuth';
|
||||||
import { SharePanel } from './SharePanel';
|
import { SharePanel } from './SharePanel';
|
||||||
@@ -334,11 +334,12 @@ export function MemeDetail({ memeId, onClose }: Props) {
|
|||||||
<dd className="text-zinc-300">{meme.mime_type.replace('image/', '').replace('video/', '')}</dd>
|
<dd className="text-zinc-300">{meme.mime_type.replace('image/', '').replace('video/', '')}</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<dt className="text-zinc-500">Shared</dt>
|
<dt className="text-zinc-500 flex items-center gap-1"><Share2 size={11} /> Shared</dt>
|
||||||
<dd className="text-zinc-300 flex items-center gap-1">
|
<dd className="text-zinc-300">{meme.share_count ?? 0} time{(meme.share_count ?? 0) !== 1 ? 's' : ''}</dd>
|
||||||
<Share2 size={11} className="text-zinc-500" />
|
</div>
|
||||||
{meme.share_count ?? 0} time{(meme.share_count ?? 0) !== 1 ? 's' : ''}
|
<div className="flex justify-between">
|
||||||
</dd>
|
<dt className="text-zinc-500 flex items-center gap-1"><MousePointerClick size={11} /> Link clicks</dt>
|
||||||
|
<dd className="text-zinc-300">{meme.view_count ?? 0}</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<dt className="text-zinc-500">Uploaded</dt>
|
<dt className="text-zinc-500">Uploaded</dt>
|
||||||
|
|||||||
Reference in New Issue
Block a user