mirror of
https://github.com/D4M13N-D3V/neroshitron.git
synced 2025-03-14 10:05:04 +00:00
fix: added tier pages
This commit is contained in:
parent
fcf83c6435
commit
19bee6998a
1
.env
1
.env
@ -1,2 +1,3 @@
|
|||||||
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
|
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
|
||||||
|
NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU
|
@ -1,72 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { createClient } from "@/utils/supabase/client";
|
|
||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
|
|
||||||
function PageComponent() {
|
|
||||||
const supabase = createClient();
|
|
||||||
|
|
||||||
const getData = async () => {
|
|
||||||
}
|
|
||||||
const fakeData = [
|
|
||||||
{ email: 'example1@example.com', ip: '192.168.0.1' },
|
|
||||||
{ email: 'example2@example.com', ip: '192.168.0.2' },
|
|
||||||
{ email: 'example3@example.com', ip: '192.168.0.3' },
|
|
||||||
{ email: 'example1@example.com', ip: '192.168.0.1' },
|
|
||||||
{ email: 'example2@example.com', ip: '192.168.0.2' },
|
|
||||||
{ email: 'example3@example.com', ip: '192.168.0.3' },
|
|
||||||
{ email: 'example1@example.com', ip: '192.168.0.1' },
|
|
||||||
{ email: 'example2@example.com', ip: '192.168.0.2' },
|
|
||||||
{ email: 'example3@example.com', ip: '192.168.0.3' },
|
|
||||||
{ email: 'example1@example.com', ip: '192.168.0.1' },
|
|
||||||
{ email: 'example2@example.com', ip: '192.168.0.2' },
|
|
||||||
{ email: 'example3@example.com', ip: '192.168.0.3' },
|
|
||||||
{ email: 'example1@example.com', ip: '192.168.0.1' },
|
|
||||||
{ email: 'example2@example.com', ip: '192.168.0.2' },
|
|
||||||
{ email: 'example3@example.com', ip: '192.168.0.3' },
|
|
||||||
{ email: 'example1@example.com', ip: '192.168.0.1' },
|
|
||||||
{ email: 'example2@example.com', ip: '192.168.0.2' },
|
|
||||||
{ email: 'example3@example.com', ip: '192.168.0.3' },
|
|
||||||
{ email: 'example1@example.com', ip: '192.168.0.1' },
|
|
||||||
{ email: 'example2@example.com', ip: '192.168.0.2' },
|
|
||||||
{ email: 'example3@example.com', ip: '192.168.0.3' },
|
|
||||||
];
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getData();
|
|
||||||
}, []);
|
|
||||||
return (
|
|
||||||
|
|
||||||
<div className="w-full text-white flex justify-center items-center animate-in">
|
|
||||||
<div className="w-2/3 rounded-md bg-primary p-12 mt-32 shadow-lg opacity-90 backdrop-blur-lg">
|
|
||||||
<div className="w-1/2 rounded-md bg-primary-dark p-12 shadow-lg opacity-90 backdrop-blur-lg">
|
|
||||||
<input type="text" className="mb-4 mr-2 rounded-md bg-primary p-2 w-full text-white" placeholder="Search all users by email" />
|
|
||||||
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th className="px-4 py-2"></th>
|
|
||||||
<th className="px-4 py-2"></th>
|
|
||||||
<th className="px-4 py-2"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="h-44">
|
|
||||||
{fakeData.map((data, index) => (
|
|
||||||
<tr key={index}>
|
|
||||||
<td className="px-4 py-2">{data.email}</td>
|
|
||||||
<td className="px-4 py-2">{data.ip}</td>
|
|
||||||
<td className="px-4 py-2"><button className="p-2 rounded w-full hover:bg-primary-light bg-primary">View</button></td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PageComponent;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
57
app/admin/tiers/create/page.tsx
Normal file
57
app/admin/tiers/create/page.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
"use client";
|
||||||
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
function PageComponent() {
|
||||||
|
const supabase = createClient();
|
||||||
|
const getData = async () => {
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getData();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div className="w-full p-8 h-1/2 text-white lg:flex justify-center items-center animate-in">
|
||||||
|
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
|
||||||
|
<div className="w-full flex">
|
||||||
|
<input type="text" onChange={(e)=>{}}
|
||||||
|
className="mr-2 rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg"
|
||||||
|
placeholder="Tag Name" />
|
||||||
|
<div className="flex border border-gray-300 w-1/2 rounded-md">
|
||||||
|
<span className="flex items-center bg-gray-100 rounded-l-md border-r px-3 text-gray-500">
|
||||||
|
$
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
placeholder="Price in USD per month"
|
||||||
|
type="number"
|
||||||
|
className="flex-1 min-w-0 bg-info-bright rounded-r-md px-3 py-2 text-black focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full pt-2 justify-center flex">
|
||||||
|
<textarea placeholder="Description of the tier and what the user gets from subscribing." rows={3} className="w-full rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg">
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
<div className="w-full pt-2 justify-center flex">
|
||||||
|
|
||||||
|
<div className="w-1/2 relative">
|
||||||
|
<input type="text" className="w-full rounded-md bg-info-bright p-2 text-black shadow-lg" onChange={(e)=>{}} placeholder="Choose the tiers color"/>
|
||||||
|
<input id="colorInput" type="color" className="absolute right-0 top-0 w-10 h-full rounded-r p-1"/>
|
||||||
|
</div>
|
||||||
|
<button onClick={()=>{}} className="hover:scale-95 ml-2 shadow-lg w-1/2 h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center">
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
<button onClick={()=>{}} className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-error-dark hover:bg-error text-white font-bold rounded flex items-center justify-center">
|
||||||
|
Back
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PageComponent;
|
||||||
|
|
||||||
|
|
||||||
|
|
61
app/admin/tiers/page.tsx
Normal file
61
app/admin/tiers/page.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"use client";
|
||||||
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
function PageComponent() {
|
||||||
|
const supabase = createClient();
|
||||||
|
const getData = async () => {
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
const fakeData = [
|
||||||
|
{
|
||||||
|
description: "Lorem ipsum dolor sit amet",
|
||||||
|
color: "#5e3573",
|
||||||
|
price: 9.99,
|
||||||
|
name: "Product 1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Consectetur adipiscing elit",
|
||||||
|
color: "#00FF00",
|
||||||
|
price: 19.99,
|
||||||
|
name: "Product 2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Sed do eiusmod tempor incididunt",
|
||||||
|
color: "#0000FF",
|
||||||
|
price: 29.99,
|
||||||
|
name: "Product 3"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// Rest of the code...
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-2/3 p-8 h-1/2 text-white lg:flex justify-center items-center animate-in">
|
||||||
|
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
|
||||||
|
<div className="w-full flex justify-center">
|
||||||
|
<button className="bg-success hover:bg-success-light rounded p-2 w-full">Create New Tier</button>
|
||||||
|
</div>
|
||||||
|
<div className="w-full justify-center pt-8">
|
||||||
|
{fakeData.map((item, index) => (
|
||||||
|
<div className="w-full flex justify-center">
|
||||||
|
<div key={index} className="text-white w-full text-stroke mt-2">
|
||||||
|
<button className="py-2 w-full rounded hover:scale-105" style={{ backgroundColor: item.color }}>{item.name}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PageComponent;
|
||||||
|
|
||||||
|
|
||||||
|
|
61
app/admin/tiers/view/page.tsx
Normal file
61
app/admin/tiers/view/page.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"use client";
|
||||||
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
function PageComponent() {
|
||||||
|
const supabase = createClient();
|
||||||
|
const getData = async () => {
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getData();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div className="w-full p-8 h-1/2 text-white lg:flex justify-center items-center animate-in">
|
||||||
|
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
|
||||||
|
<div className="w-full flex">
|
||||||
|
<input type="text" onChange={(e)=>{}}
|
||||||
|
className="mr-2 rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg"
|
||||||
|
placeholder="Tag Name" />
|
||||||
|
<div className="flex border border-gray-300 w-1/2 rounded-md">
|
||||||
|
<span className="flex items-center bg-gray-100 rounded-l-md border-r px-3 text-gray-500">
|
||||||
|
$
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
placeholder="Price in USD per month"
|
||||||
|
type="number"
|
||||||
|
className="flex-1 min-w-0 bg-info-bright rounded-r-md px-3 py-2 text-black focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full pt-2 justify-center flex">
|
||||||
|
<textarea placeholder="Description of the tier and what the user gets from subscribing." rows={3} className="w-full rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg">
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
<div className="w-full pt-2 justify-center flex">
|
||||||
|
<div className="w-1/2 relative">
|
||||||
|
<input type="text" className="w-full rounded-md bg-info-bright p-2 text-black shadow-lg" onChange={(e)=>{}} placeholder="Choose the tiers color"/>
|
||||||
|
<input id="colorInput" type="color" className="absolute right-0 top-0 w-10 h-full rounded-r p-1"/>
|
||||||
|
</div>
|
||||||
|
<div className="w-1/2 flex">
|
||||||
|
<button onClick={()=>{}} className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-warning hover:bg-warning-light text-white font-bold rounded flex items-center justify-center">
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
<button onClick={()=>{}} className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-error hover:bg-error-light text-white font-bold rounded flex items-center justify-center">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
<button onClick={()=>{}} className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-error-dark hover:bg-error text-white font-bold rounded flex items-center justify-center">
|
||||||
|
Back
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PageComponent;
|
||||||
|
|
||||||
|
|
||||||
|
|
59
app/admin/users/page.tsx
Normal file
59
app/admin/users/page.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
"use client";
|
||||||
|
import { createClient } from "@/utils/supabase/client";
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
function PageComponent() {
|
||||||
|
const supabase = createClient();
|
||||||
|
const [users, setUsers] = useState<any[]>([]);
|
||||||
|
const getData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/admin/users');
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
console.log(data)
|
||||||
|
setUsers(data.users);
|
||||||
|
} else {
|
||||||
|
console.error('Failed to fetch users');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching users:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getData();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
|
||||||
|
<div className="w-full text-white flex justify-center items-center animate-in">
|
||||||
|
<div className="w-2/3 rounded-md bg-primary p-12 mt-32 shadow-lg opacity-90 backdrop-blur-lg">
|
||||||
|
<div className="w-2/5 rounded-md bg-secondary-dark p-12 shadow-lg opacity-90 backdrop-blur-lg">
|
||||||
|
<input type="text" className="mb-4 mr-2 rounded-md bg-primary p-2 w-full text-white" placeholder="Search all users by email" />
|
||||||
|
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className="px-4 py-2"></th>
|
||||||
|
<th className="px-4 py-2"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{users.map((data, index) => (
|
||||||
|
<tr key={index} className="rounded hover:bg-primary bg-primary-light shadow-lg">
|
||||||
|
<td className="px-4 py-2">{data.email}</td>
|
||||||
|
<td className="px-4 py-2"><button className="p-2 rounded w-full hover:bg-primary-light bg-primary">View</button></td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PageComponent;
|
||||||
|
|
||||||
|
|
||||||
|
|
19
app/api/admin/users/route.tsx
Normal file
19
app/api/admin/users/route.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { createClient } from "@/utils/supabase/server";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
try {
|
||||||
|
const supabase = createClient();
|
||||||
|
|
||||||
|
const { data, error } = await supabase.auth.admin.listUsers();
|
||||||
|
console.log(error)
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json(data);
|
||||||
|
} catch (error) {
|
||||||
|
return NextResponse.error();
|
||||||
|
}
|
||||||
|
}
|
@ -2,18 +2,25 @@ import { NextResponse } from "next/server";
|
|||||||
import { createClient } from "@/utils/supabase/server";
|
import { createClient } from "@/utils/supabase/server";
|
||||||
|
|
||||||
|
|
||||||
enum customTypeOptions
|
|
||||||
{
|
|
||||||
Free,
|
|
||||||
Tier1,
|
|
||||||
Tier2,
|
|
||||||
Tier3
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const supabase = createClient();
|
const supabase = createClient();
|
||||||
|
const { data, error } = await supabase.from('tiers').select('*');
|
||||||
return NextResponse.json(customTypeOptions);
|
if (error) {
|
||||||
|
console.error('Error fetching tiers:', error);
|
||||||
|
return NextResponse.error();
|
||||||
|
}
|
||||||
|
const tiers = data ?? [];
|
||||||
|
return NextResponse.json(tiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
const supabase = createClient();
|
||||||
|
const { name, price, color, description } = await request.json();
|
||||||
|
const { data, error } = await supabase.from('tiers').insert([{ name, price, color, description }]);
|
||||||
|
if (error) {
|
||||||
|
console.error('Error inserting tier:', error);
|
||||||
|
return NextResponse.error();
|
||||||
|
}
|
||||||
|
return NextResponse.json(data);
|
||||||
|
}
|
||||||
|
|
@ -69,74 +69,34 @@ function PageComponent() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full p-8 h-1/2 text-white lg:flex justify-center items-center animate-in">
|
<div className="w-full p-8 h-max text-white lg:flex justify-center items-center animate-in">
|
||||||
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
|
<div className="w-full h-max lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
|
||||||
<div className="w-full flex">
|
<div className="w-full flex">
|
||||||
<input value={newTagName} type="text" onChange={(e)=>{setNewTagName(e.target.value)}} className="hover:scale-105 focus:scale-105 mb-8 mr-2 rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg" placeholder="Tag Name" />
|
<input value={newTagName} type="text" onChange={(e)=>{setNewTagName(e.target.value)}} className="hover:scale-105 focus:scale-105 mb-8 mr-2 rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg" placeholder="Tag Name" />
|
||||||
<button onClick={createTag} className="hover:scale-95 ml-2 shadow-lg w-1/2 h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center">
|
<button onClick={createTag} className="hover:scale-95 ml-2 shadow-lg w-1/2 h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="lg:hidden size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="lg:hidden size-6">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<span className="lg:hidden block">Tag</span>
|
<span className="lg:hidden block">Tag</span>
|
||||||
<span className="lg:block hidden">New Tag</span>
|
<span className="lg:block hidden">New Tag</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
<div className="w-full flex">
|
|
||||||
<input type="text" value={tagSearch} onChange={(e)=>{setTagSearch(e.target.value)}} className="hover:scale-105 focus:scale-105 mb-8 shadow-lg mr-2 rounded-md bg-info-bright p-2 w-full text-black" placeholder="Search all tags by name" />
|
|
||||||
</div>
|
|
||||||
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
|
||||||
<table className="w-full bg-primary-light rounded">
|
|
||||||
<tbody>
|
|
||||||
{tags.filter((value,index,array)=>{
|
|
||||||
return value.name.toLowerCase().includes(tagSearch.toLowerCase());
|
|
||||||
}).map((item:any) => (
|
|
||||||
<tr key={item.name} className="hover:bg-secondary-dark animate-in shadow">
|
|
||||||
<td className="px-4 py-2">{item.name}</td>
|
|
||||||
<td className="px-4 py-2">
|
|
||||||
<button onClick={()=>{deleteTag(item.name)}} className="hover:scale-95 bg-error shadow-lg hover:bg-error-light text-white font-bold py-2 px-4 rounded float-right">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full lg:w-1/2 h-max rounded-md bg-primary opacity-90 backdrop-blur-lg p-12 m-1 mt-32 shadow-lg">
|
|
||||||
<div className="w-full fixed flex pb-2 z-20">
|
|
||||||
<div className="w-4/6">
|
|
||||||
<SearchInput
|
|
||||||
startingTags={[]}
|
|
||||||
placeholderTags={[
|
|
||||||
{ value: "tags", label: "❗️ click here to add tags to search" }
|
|
||||||
]} nsfwButtonEnabled={false} searchChanged={(search) => { setSearchState(search) }} nsfwChanged={(nsfw) => { setNsfwState(nsfw) }} tagsChanged={(tags) => { setTagsState(tags) }} />
|
|
||||||
</div>
|
</div>
|
||||||
<a href="/gallery/admin/create" className="w-1/6 hover:scale-95 ml-2 p-2 shadow-lg h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center">
|
<div className="w-full flex">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="xl:hidden size-6">
|
<input type="text" value={tagSearch} onChange={(e)=>{setTagSearch(e.target.value)}} className="hover:scale-105 focus:scale-105 mb-8 shadow-lg mr-2 rounded-md bg-info-bright p-2 w-full text-black" placeholder="Search all tags by name" />
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
</div>
|
||||||
</svg>
|
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
||||||
|
<table className="w-full bg-primary-light rounded">
|
||||||
<span className="xl:block hidden">New Gallery</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
|
||||||
<table className="w-full mt-20 bg-primary-light rounded">
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{/* Replace this with your data mapping logic */}
|
{tags.filter((value,index,array)=>{
|
||||||
{galleries.map((item: { name: string, imageCount: number, tier: string }) => (
|
return value.name.toLowerCase().includes(tagSearch.toLowerCase());
|
||||||
<tr key={item.name} className="hover:bg-secondary-dark shadow animate-in">
|
}).map((item:any) => (
|
||||||
<td className="px-4 py-2" style={{ width: '65%' }}>{item.name}</td>
|
<tr key={item.name} className="hover:bg-secondary-dark animate-in shadow">
|
||||||
<td className="px-4 py-2">{item.imageCount}</td>
|
<td className="px-4 py-2">{item.name}</td>
|
||||||
<td className="px-4 py-2">{item.tier}</td>
|
|
||||||
<td className="px-4 py-2">
|
<td className="px-4 py-2">
|
||||||
<button onClick={()=>{ window.location.href=`/gallery/admin/view?id=${encodeURIComponent(item.name)}`}} className="bg-secondary hover:scale-95 shadow-lg hover:bg-secondary-light text-white font-bold py-2 px-4 rounded float-right">
|
<button onClick={()=>{deleteTag(item.name)}} className="hover:scale-95 bg-error shadow-lg hover:bg-error-light text-white font-bold py-2 px-4 rounded float-right">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m5.231 13.481L15 17.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v16.5c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Zm3.75 11.625a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
@ -145,8 +105,47 @@ function PageComponent() {
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full h-max lg:w-1/2 rounded-md bg-primary opacity-90 backdrop-blur-lg p-12 shadow-lg">
|
||||||
|
<div className="w-full fixed flex pb-2 z-20">
|
||||||
|
<div className="w-4/6">
|
||||||
|
<SearchInput
|
||||||
|
startingTags={[]}
|
||||||
|
placeholderTags={[
|
||||||
|
{ value: "tags", label: "❗️ click here to add tags to search" }
|
||||||
|
]} nsfwButtonEnabled={false} searchChanged={(search) => { setSearchState(search) }} nsfwChanged={(nsfw) => { setNsfwState(nsfw) }} tagsChanged={(tags) => { setTagsState(tags) }} />
|
||||||
|
</div>
|
||||||
|
<a href="/gallery/admin/create" className="w-1/6 hover:scale-95 ml-2 p-2 shadow-lg h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="xl:hidden size-6">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span className="xl:block hidden">New Gallery</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
||||||
|
<table className="w-full mt-20 bg-primary-light rounded">
|
||||||
|
<tbody>
|
||||||
|
{/* Replace this with your data mapping logic */}
|
||||||
|
{galleries.map((item: { name: string, imageCount: number, tier: string }) => (
|
||||||
|
<tr key={item.name} className="hover:bg-secondary-dark shadow animate-in">
|
||||||
|
<td className="px-4 py-2" style={{ width: '65%' }}>{item.name}</td>
|
||||||
|
<td className="px-4 py-2">{item.imageCount}</td>
|
||||||
|
<td className="px-4 py-2">{item.tier}</td>
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
<button onClick={()=>{ window.location.href=`/gallery/admin/view?id=${encodeURIComponent(item.name)}`}} className="bg-secondary hover:scale-95 shadow-lg hover:bg-secondary-light text-white font-bold py-2 px-4 rounded float-right">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m5.231 13.481L15 17.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v16.5c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Zm3.75 11.625a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -173,8 +173,8 @@ function PageComponent() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-1/4">
|
<div className="w-1/4">
|
||||||
<button onClick={()=>{updateGallery()}} className="w-full bg-success hover:bg-success-light text-white rounded-md p-2 ml-4">
|
<button onClick={()=>{updateGallery()}} className="w-full bg-warning hover:bg-warning-light text-white rounded-md p-2 ml-4">
|
||||||
<span>Save</span>
|
<span>Update</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@ export const createClient = () => {
|
|||||||
|
|
||||||
return createServerClient(
|
return createServerClient(
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
process.env.NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY!,
|
||||||
{
|
{
|
||||||
cookies: {
|
cookies: {
|
||||||
get(name: string) {
|
get(name: string) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user