enh
This commit is contained in:
parent
ed7318f9ee
commit
dc644aef7e
5 changed files with 226 additions and 11 deletions
|
|
@ -1,6 +1,6 @@
|
|||
ENV_MODE=PROD
|
||||
DATABASE_URL=postgresql://postgres:meatfarmer_master_password@57.128.212.174:7447/meatfarmer #technocracy
|
||||
# DATABASE_URL=postgres://postgres:meatfarmer_master_password@5.223.55.14:7447/meatfarmer #hetzner
|
||||
# DATABASE_URL=postgresql://postgres:meatfarmer_master_password@57.128.212.174:7447/meatfarmer #technocracy
|
||||
DATABASE_URL=postgres://postgres:meatfarmer_master_password@5.223.55.14:7447/meatfarmer #hetzner
|
||||
PHONE_PE_BASE_URL=https://api-preprod.phonepe.com/
|
||||
PHONE_PE_CLIENT_ID=TEST-M23F2IGP34ZAR_25090
|
||||
PHONE_PE_CLIENT_VERSION=1
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { UserHomeRoute } from './routes/user-home'
|
|||
import { SuperAdminRoute } from './routes/super-admin'
|
||||
import { CreateCouponRoute } from './routes/create-coupon'
|
||||
import { LocationMarkerRoute } from './routes/location-marker'
|
||||
import { UserConnectRoute } from './routes/user-connect'
|
||||
import Inauguration from './routes/inauguration'
|
||||
import { AuthWrapper } from './components/AuthWrapper'
|
||||
import { SuperAdminGuard } from './components/SuperAdminGuard'
|
||||
|
|
@ -101,6 +102,18 @@ const createCouponRoute = new Route({
|
|||
)
|
||||
})
|
||||
|
||||
const userConnectRoute = new Route({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/user-connect',
|
||||
component: () => (
|
||||
<Suspense fallback={<p>Loading user connect…</p>}>
|
||||
<AuthWrapper>
|
||||
<UserConnectRoute />
|
||||
</AuthWrapper>
|
||||
</Suspense>
|
||||
)
|
||||
})
|
||||
|
||||
const locationMarkerRoute = new Route({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/location-marker',
|
||||
|
|
@ -118,6 +131,7 @@ const routeTree = rootRoute.addChildren([
|
|||
userHomeRoute,
|
||||
superAdminRoute,
|
||||
createCouponRoute,
|
||||
userConnectRoute,
|
||||
locationMarkerRoute,
|
||||
inaugurationRoute
|
||||
])
|
||||
|
|
@ -139,7 +153,8 @@ declare module '@tanstack/react-router' {
|
|||
|
||||
const navItems = [
|
||||
{ to: '/', label: 'Dashboard', exact: true },
|
||||
{ to: '/vendor-order-list', label: 'Vendor Order List' }
|
||||
{ to: '/vendor-order-list', label: 'Vendor Order List' },
|
||||
{ to: '/user-connect', label: 'User Connect' }
|
||||
] as const
|
||||
|
||||
function RootComponent() {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,33 @@
|
|||
import { useNavigate } from '@tanstack/react-router'
|
||||
import { useUserStore } from '@/stores/userStore'
|
||||
import { removeAuthToken } from '@/services/auth'
|
||||
import { StaffUserForm } from '@/components/StaffUserForm';
|
||||
|
||||
export function SuperAdminRoute() {
|
||||
const navigate = useNavigate()
|
||||
const clearUser = useUserStore((state) => state.clearUser)
|
||||
|
||||
const handleLogout = async () => {
|
||||
await removeAuthToken()
|
||||
clearUser()
|
||||
navigate({ to: '/login' as any })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto space-y-6">
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">Super Admin Dashboard</h1>
|
||||
<p className="text-gray-600">Advanced system management and user administration</p>
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">Super Admin Dashboard</h1>
|
||||
<p className="text-gray-600">Advanced system management and user administration</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
|
|
|
|||
175
apps/fallback-ui/src/routes/user-connect.tsx
Normal file
175
apps/fallback-ui/src/routes/user-connect.tsx
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
import { useState } from 'react'
|
||||
import { trpc } from '@/trpc/client'
|
||||
|
||||
export function UserConnectRoute() {
|
||||
const [search, setSearch] = useState('')
|
||||
const [searchInput, setSearchInput] = useState('')
|
||||
const [cursor, setCursor] = useState<number | undefined>(undefined)
|
||||
|
||||
const { data, isLoading, error } = trpc.admin.user.getAllUsers.useQuery({
|
||||
limit: 50,
|
||||
cursor,
|
||||
search,
|
||||
})
|
||||
|
||||
const handleSearch = () => {
|
||||
setSearch(searchInput)
|
||||
setCursor(undefined)
|
||||
}
|
||||
|
||||
const handleNextPage = () => {
|
||||
if (data?.nextCursor) {
|
||||
setCursor(data.nextCursor)
|
||||
}
|
||||
}
|
||||
|
||||
const handlePrevPage = () => {
|
||||
setCursor(undefined)
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<p className="text-gray-600 text-center">Loading users...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<p className="text-red-600 text-center">Error loading users: {error.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto space-y-6">
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">User Connect</h1>
|
||||
<p className="text-gray-600">View all registered users and their contact information</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<div className="flex gap-2 mb-4">
|
||||
<input
|
||||
type="text"
|
||||
value={searchInput}
|
||||
onChange={(e) => setSearchInput(e.target.value)}
|
||||
placeholder="Search by mobile number..."
|
||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleSearch()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onClick={handleSearch}
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
{search && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearch('')
|
||||
setSearchInput('')
|
||||
setCursor(undefined)
|
||||
}}
|
||||
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="border-b border-gray-200">
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-700">ID</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-700">Name</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-700">Mobile</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-700">Total Orders</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-700">Last Order</th>
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-700">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data?.users.map((user) => (
|
||||
<tr key={user.id} className="border-b border-gray-100 hover:bg-gray-50">
|
||||
<td className="py-3 px-4 text-gray-600">{user.id}</td>
|
||||
<td className="py-3 px-4 text-gray-900">{user.name || '-'}</td>
|
||||
<td className="py-3 px-4">
|
||||
{user.mobile ? (
|
||||
<a
|
||||
href={`https://wa.me/91${user.mobile.replace(/\D/g, '')}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 hover:text-blue-800 font-mono hover:underline"
|
||||
>
|
||||
{user.mobile}
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-gray-400">-</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="py-3 px-4 text-gray-600">{user.totalOrders}</td>
|
||||
<td className="py-3 px-4 text-gray-600">
|
||||
{user.lastOrderDate
|
||||
? new Date(user.lastOrderDate).toLocaleDateString()
|
||||
: '-'}
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
{user.isSuspended ? (
|
||||
<span className="px-2 py-1 bg-red-100 text-red-700 text-xs font-medium rounded">
|
||||
Suspended
|
||||
</span>
|
||||
) : (
|
||||
<span className="px-2 py-1 bg-green-100 text-green-700 text-xs font-medium rounded">
|
||||
Active
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{data?.users.length === 0 && (
|
||||
<p className="text-center text-gray-500 py-8">No users found</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center mt-4 pt-4 border-t border-gray-200">
|
||||
<p className="text-sm text-gray-600">
|
||||
Showing {data?.users.length || 0} users
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
{cursor !== undefined && (
|
||||
<button
|
||||
onClick={handlePrevPage}
|
||||
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
)}
|
||||
{data?.hasMore && (
|
||||
<button
|
||||
onClick={handleNextPage}
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -26,18 +26,21 @@ function AdminDashboard() {
|
|||
</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div className="bg-blue-50 p-4 rounded-lg">
|
||||
<Link
|
||||
to="/user-connect"
|
||||
className="bg-blue-50 p-4 rounded-lg hover:bg-blue-100 transition-colors"
|
||||
>
|
||||
<h3 className="font-semibold text-blue-900 mb-2">User Management</h3>
|
||||
<p className="text-blue-700 text-sm">Manage staff users and permissions</p>
|
||||
</div>
|
||||
<div className="bg-green-50 p-4 rounded-lg">
|
||||
<p className="text-blue-700 text-sm">View all users and their contact info</p>
|
||||
</Link>
|
||||
{/*<div className="bg-green-50 p-4 rounded-lg">
|
||||
<h3 className="font-semibold text-green-900 mb-2">System Settings</h3>
|
||||
<p className="text-green-700 text-sm">Configure system-wide settings</p>
|
||||
</div>
|
||||
<div className="bg-purple-50 p-4 rounded-lg">
|
||||
<h3 className="font-semibold text-purple-900 mb-2">Analytics</h3>
|
||||
<p className="text-purple-700 text-sm">View system analytics and reports</p>
|
||||
</div>
|
||||
</div>*/}
|
||||
{user?.role?.name === 'super_admin' && (
|
||||
<Link
|
||||
to="/super-admin"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue