Compare commits
2 Commits
8c7f4000a9
...
52190ff26d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52190ff26d | ||
|
|
5ae1632684 |
@@ -449,7 +449,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
className={editor.isActive('bold') ? 'bg-accent' : ''}
|
||||
className={editor.isActive('bold') ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<Bold className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -458,7 +458,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
className={editor.isActive('italic') ? 'bg-accent' : ''}
|
||||
className={editor.isActive('italic') ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<Italic className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -467,7 +467,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
className={editor.isActive('heading', { level: 1 }) ? 'bg-accent' : ''}
|
||||
className={editor.isActive('heading', { level: 1 }) ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<Heading1 className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -476,7 +476,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
className={editor.isActive('heading', { level: 2 }) ? 'bg-accent' : ''}
|
||||
className={editor.isActive('heading', { level: 2 }) ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<Heading2 className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -485,7 +485,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
className={editor.isActive('bulletList') ? 'bg-accent' : ''}
|
||||
className={editor.isActive('bulletList') ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<List className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -494,7 +494,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
className={editor.isActive('orderedList') ? 'bg-accent' : ''}
|
||||
className={editor.isActive('orderedList') ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<ListOrdered className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -503,7 +503,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
className={editor.isActive('blockquote') ? 'bg-accent' : ''}
|
||||
className={editor.isActive('blockquote') ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<Quote className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -512,7 +512,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={addLink}
|
||||
className={editor.isActive('link') ? 'bg-accent' : ''}
|
||||
className={editor.isActive('link') ? 'bg-primary text-primary-foreground' : ''}
|
||||
>
|
||||
<LinkIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -628,7 +628,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
<div onPaste={handlePaste}>
|
||||
<EditorContent
|
||||
editor={editor}
|
||||
className="prose prose-sm max-w-none p-4 min-h-[200px] focus:outline-none [&_.ProseMirror]:outline-none [&_.ProseMirror]:min-h-[180px] [&_img]:cursor-pointer [&_img.ProseMirror-selectednode]:ring-2 [&_img.ProseMirror-selectednode]:ring-primary"
|
||||
className="prose prose-sm max-w-none p-4 min-h-[200px] focus:outline-none [&_.ProseMirror]:outline-none [&_.ProseMirror]:min-h-[180px] [&_img]:cursor-pointer [&_img.ProseMirror-selectednode]:ring-2 [&_img.ProseMirror-selectednode]:ring-primary [&_h1]:font-bold [&_h1]:text-2xl [&_h1]:mb-4 [&_h1]:mt-6 [&_h2]:font-bold [&_h2]:text-xl [&_h2]:mb-3 [&_h2]:mt-5 [&_blockquote]:border-l-4 [&_blockquote]:border-primary [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:text-muted-foreground [&_blockquote]:my-4"
|
||||
/>
|
||||
</div>
|
||||
{uploading && (
|
||||
|
||||
@@ -267,7 +267,7 @@ export default function ProductDetail() {
|
||||
Gabung Webinar
|
||||
</a>
|
||||
</Button>
|
||||
) : <Badge className="bg-secondary">Rekaman segera tersedia</Badge>;
|
||||
) : <Badge className="bg-primary text-primary-foreground">Rekaman segera tersedia</Badge>;
|
||||
case 'bootcamp':
|
||||
return (
|
||||
<Button onClick={() => navigate(`/bootcamp/${product.slug}`)} size="lg" className="shadow-sm">
|
||||
@@ -346,8 +346,8 @@ export default function ProductDetail() {
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">{product.title}</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge className="bg-secondary capitalize">{product.type}</Badge>
|
||||
{hasAccess && <Badge className="bg-accent">Anda memiliki akses</Badge>}
|
||||
<Badge className="bg-primary text-primary-foreground capitalize">{product.type}</Badge>
|
||||
{hasAccess && <Badge className="bg-primary text-primary-foreground">Anda memiliki akses</Badge>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
|
||||
@@ -580,7 +580,13 @@ export default function AdminConsulting() {
|
||||
</Tabs>
|
||||
|
||||
{/* Meet Link Dialog */}
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<Dialog open={dialogOpen} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
const confirmed = window.confirm('Tutup dialog? Data yang belum disimpan akan hilang.');
|
||||
if (!confirmed) return;
|
||||
}
|
||||
setDialogOpen(open);
|
||||
}}>
|
||||
<DialogContent className="max-w-md border-2 border-border">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Link Google Meet</DialogTitle>
|
||||
|
||||
@@ -432,7 +432,13 @@ export default function AdminEvents() {
|
||||
</Tabs>
|
||||
|
||||
{/* Event Dialog */}
|
||||
<Dialog open={eventDialogOpen} onOpenChange={setEventDialogOpen}>
|
||||
<Dialog open={eventDialogOpen} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
const confirmed = window.confirm('Tutup dialog? Data yang belum disimpan akan hilang.');
|
||||
if (!confirmed) return;
|
||||
}
|
||||
setEventDialogOpen(open);
|
||||
}}>
|
||||
<DialogContent className="max-w-md border-2 border-border">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{editingEvent ? 'Edit Event' : 'Buat Event Baru'}</DialogTitle>
|
||||
@@ -504,7 +510,13 @@ export default function AdminEvents() {
|
||||
</Dialog>
|
||||
|
||||
{/* Block Dialog */}
|
||||
<Dialog open={blockDialogOpen} onOpenChange={setBlockDialogOpen}>
|
||||
<Dialog open={blockDialogOpen} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
const confirmed = window.confirm('Tutup dialog? Data yang belum disimpan akan hilang.');
|
||||
if (!confirmed) return;
|
||||
}
|
||||
setBlockDialogOpen(open);
|
||||
}}>
|
||||
<DialogContent className="max-w-md border-2 border-border">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{editingBlock ? 'Edit Blok' : 'Tambah Blok Ketersediaan'}</DialogTitle>
|
||||
|
||||
@@ -205,7 +205,13 @@ export default function AdminMembers() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<Dialog open={dialogOpen} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
const confirmed = window.confirm('Tutup dialog? Data yang belum disimpan akan hilang.');
|
||||
if (!confirmed) return;
|
||||
}
|
||||
setDialogOpen(open);
|
||||
}}>
|
||||
<DialogContent className="max-w-lg border-2 border-border">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Detail Member</DialogTitle>
|
||||
|
||||
@@ -262,7 +262,13 @@ export default function AdminOrders() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<Dialog open={dialogOpen} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
const confirmed = window.confirm('Tutup dialog? Data yang belum disimpan akan hilang.');
|
||||
if (!confirmed) return;
|
||||
}
|
||||
setDialogOpen(open);
|
||||
}}>
|
||||
<DialogContent className="max-w-lg border-2 border-border">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Detail Order</DialogTitle>
|
||||
|
||||
@@ -267,7 +267,13 @@ export default function AdminProducts() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<Dialog open={dialogOpen} onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
const confirmed = window.confirm('Tutup dialog? Data yang belum disimpan akan hilang.');
|
||||
if (!confirmed) return;
|
||||
}
|
||||
setDialogOpen(open);
|
||||
}}>
|
||||
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto border-2 border-border">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{editingProduct ? 'Edit Produk' : 'Produk Baru'}</DialogTitle>
|
||||
|
||||
@@ -66,18 +66,24 @@ export default function MemberDashboard() {
|
||||
qr_expires_at
|
||||
)
|
||||
`)
|
||||
.eq('orders.payment_status', 'pending')
|
||||
.eq('status', 'pending_payment')
|
||||
.gt('orders.qr_expires_at', new Date().toISOString())
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
if (!error && data) {
|
||||
// Filter in JavaScript: only include slots where order is pending AND not expired
|
||||
const now = new Date().toISOString();
|
||||
const validSlots = data.filter((item: any) =>
|
||||
item.orders?.payment_status === 'pending' &&
|
||||
item.orders?.qr_expires_at &&
|
||||
item.orders.qr_expires_at > now
|
||||
);
|
||||
|
||||
// Get unique order IDs
|
||||
const uniqueOrders = Array.from(
|
||||
new Set(data.map((item: any) => item.order_id))
|
||||
new Set(validSlots.map((item: any) => item.order_id))
|
||||
).map((orderId) => {
|
||||
// Find the corresponding order data
|
||||
const orderData = data.find((item: any) => item.order_id === orderId);
|
||||
const orderData = validSlots.find((item: any) => item.order_id === orderId);
|
||||
return {
|
||||
order_id: orderId,
|
||||
qr_expires_at: (orderData as any)?.orders?.qr_expires_at || ''
|
||||
|
||||
Reference in New Issue
Block a user