feat: add text color

This commit is contained in:
2026-02-19 23:18:30 +03:30
parent 9aff48019d
commit 74f2a82a0e
12 changed files with 44 additions and 40 deletions
+1 -1
View File
@@ -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">
+9 -12
View File
@@ -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>
+1 -1
View File
@@ -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
View File
@@ -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: '/',
+7 -7
View File
@@ -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>
+5 -9
View File
@@ -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)}
+4 -4
View File
@@ -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') {
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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)}
+13 -1
View File
@@ -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
View File
@@ -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> => {
-1
View File
@@ -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]) => {