feat: add text color
This commit is contained in:
@@ -24,7 +24,7 @@ export default function Dashboard() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-t pt-6">
|
<div className="border-t pt-6">
|
||||||
<h2 className="text-lg font-semibold mb-4">خوش آمدید، {user?.email}</h2>
|
<h2 className="text-lg font-semibold mb-4 text-slate-900">خوش آمدید، {user?.email}</h2>
|
||||||
|
|
||||||
{/* Dashboard Cards */}
|
{/* Dashboard Cards */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-6">
|
||||||
|
|||||||
@@ -40,16 +40,13 @@ export default function LoginPage() {
|
|||||||
<div className="max-w-md w-full space-y-8">
|
<div className="max-w-md w-full space-y-8">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||||
Admin Login
|
پنل ادمین اپروایجنسی
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-2 text-center text-sm text-gray-600">
|
|
||||||
Meditation App Admin Panel
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
|
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
|
||||||
<div className="rounded-md shadow-sm -space-y-px">
|
|
||||||
<div>
|
<div>
|
||||||
|
<div className='py-2'>
|
||||||
<label htmlFor="auth" className="sr-only">
|
<label htmlFor="auth" className="sr-only">
|
||||||
Email
|
Email
|
||||||
</label>
|
</label>
|
||||||
@@ -58,8 +55,8 @@ export default function LoginPage() {
|
|||||||
name="auth"
|
name="auth"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
|
className="appearance-none relative block w-full px-3 py-3 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
|
||||||
placeholder="Email"
|
placeholder="ایمیل"
|
||||||
value={auth}
|
value={auth}
|
||||||
onChange={(e) => setAuth(e.target.value)}
|
onChange={(e) => setAuth(e.target.value)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
@@ -74,8 +71,8 @@ export default function LoginPage() {
|
|||||||
name="password"
|
name="password"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
|
className="appearance-none rounded-md relative block w-full px-3 py-3 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
|
||||||
placeholder="Password"
|
placeholder="رمز عبور"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
@@ -99,9 +96,9 @@ export default function LoginPage() {
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
className="group relative w-full flex justify-center py-3 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{isLoading ? 'Logging in...' : 'Sign in'}
|
{isLoading ? 'کمی صبر کنید' : 'ورود'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ export default function ProductsPage() {
|
|||||||
id="package"
|
id="package"
|
||||||
value={selectedPackage?.name || ''}
|
value={selectedPackage?.name || ''}
|
||||||
onChange={handlePackageChange}
|
onChange={handlePackageChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
>
|
>
|
||||||
{packages.map((pkg) => (
|
{packages.map((pkg) => (
|
||||||
<option key={pkg.id} value={pkg.name || ''}>
|
<option key={pkg.id} value={pkg.name || ''}>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ import type { Metadata } from 'next';
|
|||||||
import './globals.css';
|
import './globals.css';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'آرام لند | تمرین تنفسی و مدیتیشن',
|
title: 'پنل ادمین',
|
||||||
|
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: '/',
|
canonical: '/',
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoadin
|
|||||||
required
|
required
|
||||||
value={formData.name || ''}
|
value={formData.name || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
placeholder="مثال: com.approagency.meditation"
|
placeholder="مثال: com.approagency.meditation"
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
/>
|
/>
|
||||||
@@ -127,7 +127,7 @@ export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoadin
|
|||||||
required
|
required
|
||||||
value={formData.title || ''}
|
value={formData.title || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
placeholder="مثال: آرام لند"
|
placeholder="مثال: آرام لند"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -180,7 +180,7 @@ export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoadin
|
|||||||
name="v1_identifier"
|
name="v1_identifier"
|
||||||
value={formData.v1_identifier || ''}
|
value={formData.v1_identifier || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoadin
|
|||||||
name="myket_access_token"
|
name="myket_access_token"
|
||||||
value={formData.myket_access_token || ''}
|
value={formData.myket_access_token || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoadin
|
|||||||
name="cafe_config_id"
|
name="cafe_config_id"
|
||||||
value={formData.cafe_config_id || ''}
|
value={formData.cafe_config_id || ''}
|
||||||
onChange={handleNumberChange}
|
onChange={handleNumberChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoadin
|
|||||||
name="web_app_url"
|
name="web_app_url"
|
||||||
value={formData.web_app_url || ''}
|
value={formData.web_app_url || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
placeholder="https://example.com"
|
placeholder="https://example.com"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -241,7 +241,7 @@ export default function PackageForm({ package: pkg, onSubmit, onCancel, isLoadin
|
|||||||
name="tries"
|
name="tries"
|
||||||
value={formData.tries || 0}
|
value={formData.tries || 0}
|
||||||
onChange={handleNumberChange}
|
onChange={handleNumberChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function PackageList({ packages, onEdit, onDelete, isLoading }: P
|
|||||||
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
|
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
|
||||||
<ul className="divide-y divide-gray-200">
|
<ul className="divide-y divide-gray-200">
|
||||||
{packages.map((pkg) => (
|
{packages.map((pkg) => (
|
||||||
<li key={pkg.id} className="px-6 py-4 hover:bg-gray-50">
|
<li key={pkg.id} className="px-2 py-4 hover:bg-gray-50">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center space-x-3 space-x-reverse">
|
<div className="flex items-center space-x-3 space-x-reverse">
|
||||||
@@ -44,22 +44,18 @@ export default function PackageList({ packages, onEdit, onDelete, isLoading }: P
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-indigo-600 truncate">
|
<p className="text-sm font-medium text-indigo-600 truncate px-2">
|
||||||
{pkg.title || 'بدون عنوان'}
|
{pkg.title || 'بدون عنوان'}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500 px-2">
|
||||||
{pkg.name || 'بدون نام'}
|
{pkg.name || 'بدون نام'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 sm:flex sm:justify-between">
|
<div className="mt-2 sm:flex sm:justify-between">
|
||||||
<div className="sm:flex sm:space-x-4 sm:space-x-reverse">
|
<div className="sm:flex sm:space-x-4 sm:space-x-reverse">
|
||||||
<p className="text-xs text-gray-500">
|
|
||||||
شناسه: {pkg.uuid?.substring(0, 8)}...
|
|
||||||
</p>
|
|
||||||
<p className="text-xs text-gray-500 mt-1 sm:mt-0">
|
|
||||||
تلاشها: {pkg.tries || 0}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-gray-500 mt-1 sm:mt-0">
|
<p className="text-xs text-gray-500 mt-1 sm:mt-0">
|
||||||
آخرین بهروزرسانی: {formatDate(pkg.updated_at)}
|
آخرین بهروزرسانی: {formatDate(pkg.updated_at)}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export default function ProductForm({ product, packageName, onSubmit, onCancel,
|
|||||||
required
|
required
|
||||||
value={formData.title || ''}
|
value={formData.title || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
placeholder="مثال: اشتراک ماهانه"
|
placeholder="مثال: اشتراک ماهانه"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -102,7 +102,7 @@ export default function ProductForm({ product, packageName, onSubmit, onCancel,
|
|||||||
min="0"
|
min="0"
|
||||||
value={formData.price || ''}
|
value={formData.price || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
placeholder="مثال: 60000"
|
placeholder="مثال: 60000"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,7 +118,7 @@ export default function ProductForm({ product, packageName, onSubmit, onCancel,
|
|||||||
required
|
required
|
||||||
value={formData.type || 4}
|
value={formData.type || 4}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
>
|
>
|
||||||
{Object.entries(PRODUCT_TYPES).map(([value, label]) => (
|
{Object.entries(PRODUCT_TYPES).map(([value, label]) => (
|
||||||
<option key={value} value={value}>
|
<option key={value} value={value}>
|
||||||
@@ -139,7 +139,7 @@ export default function ProductForm({ product, packageName, onSubmit, onCancel,
|
|||||||
type="text"
|
type="text"
|
||||||
value={newDescription}
|
value={newDescription}
|
||||||
onChange={(e) => setNewDescription(e.target.value)}
|
onChange={(e) => setNewDescription(e.target.value)}
|
||||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="flex-1 px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
placeholder="ویژگی جدید را وارد کنید"
|
placeholder="ویژگی جدید را وارد کنید"
|
||||||
onKeyPress={(e) => {
|
onKeyPress={(e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function PackageSelector({ token, selectedPackage, onPackageChang
|
|||||||
value={selectedPackage || ''}
|
value={selectedPackage || ''}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
disabled={loading || isLoading}
|
disabled={loading || isLoading}
|
||||||
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:opacity-50"
|
className="block w-full px-3 py-2 text-slate-900 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<option>در حال بارگذاری...</option>
|
<option>در حال بارگذاری...</option>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function UserSearch({ onSearch, isLoading }: UserSearchProps) {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="search"
|
id="search"
|
||||||
className="block w-full pr-10 pl-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
className="block w-full pr-10 pl-3 py-2 border text-slate-900 border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
placeholder="جستجو با ایمیل یا شماره موبایل..."
|
placeholder="جستجو با ایمیل یا شماره موبایل..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
|||||||
@@ -98,9 +98,19 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear localStorage
|
||||||
localStorage.removeItem('auth_token');
|
localStorage.removeItem('auth_token');
|
||||||
localStorage.removeItem('auth_user');
|
localStorage.removeItem('auth_user');
|
||||||
|
|
||||||
|
// Clear cookie - multiple methods to ensure it's removed
|
||||||
|
document.cookie = 'auth_token=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=Strict';
|
||||||
|
document.cookie = 'auth_token=; path=/admin; expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=Strict';
|
||||||
|
|
||||||
|
// Alternative: Clear all cookies
|
||||||
|
document.cookie.split(";").forEach(function (c) {
|
||||||
|
document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=; path=/; expires=" + new Date().toUTCString() + ";");
|
||||||
|
});
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
user: null,
|
user: null,
|
||||||
token: null,
|
token: null,
|
||||||
@@ -108,7 +118,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
router.push('/admin/login');
|
// Force hard navigation instead of router.push
|
||||||
|
window.location.href = '/admin/login';
|
||||||
|
// router.push('/admin/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ export const authApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
logout: async (token: string): Promise<void> => {
|
logout: async (token: string): Promise<void> => {
|
||||||
return apiClient.post('/auth/logout', {}, token);
|
return apiClient.put('/auth/logout', {}, token);
|
||||||
},
|
},
|
||||||
|
|
||||||
getProfile: async (token: string): Promise<any> => {
|
getProfile: async (token: string): Promise<any> => {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export const packagesApi = {
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
// Add method spoofing for Laravel
|
// Add method spoofing for Laravel
|
||||||
formData.append('_method', 'PUT');
|
|
||||||
|
|
||||||
// Append all fields to FormData
|
// Append all fields to FormData
|
||||||
Object.entries(data).forEach(([key, value]) => {
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user