Files
igny8/frontend/src/pages/Thinker/AuthorProfiles.tsx
IGNY8 VPS (Salman) d7220aeb91 UX Text Improvements: Thinker Module Pages
- Updated page titles to be more descriptive:
  * Prompts: 'AI Prompts Management' → 'Customize Your AI Writer'
  * AuthorProfiles: 'Author Profiles' → 'Choose Your Writing Voice'
  * Strategies: 'Content Strategies' → 'Your Content Strategies'
  * ImageTesting: 'Image Testing' → 'Test Your Image Generator'
  * Dashboard: 'Thinker Dashboard' → 'Your AI Configuration Dashboard'

- Updated navigation tab labels across all Thinker pages:
  * 'Prompts' → 'AI Instructions'
  * 'Author Profiles' → 'Writing Voices'
  * 'Strategies' → 'Content Strategies'
  * 'Image Testing' stays the same

- Updated Prompts page section titles:
  * 'Planner Prompts' → 'Keyword & Topic Instructions'
  * 'Writer Prompts' → 'Article Writing Instructions'
  * Updated descriptions to be more conversational

Part of comprehensive UX text improvement initiative.
2025-12-25 06:32:15 +00:00

176 lines
6.2 KiB
TypeScript

import { useState, useEffect } from 'react';
import PageMeta from '../../components/common/PageMeta';
import PageHeader from '../../components/common/PageHeader';
import ModuleNavigationTabs from '../../components/navigation/ModuleNavigationTabs';
import { useToast } from '../../components/ui/toast/ToastContainer';
import { fetchAuthorProfiles, createAuthorProfile, updateAuthorProfile, deleteAuthorProfile, AuthorProfile } from '../../services/api';
import { Card } from '../../components/ui/card';
import Button from '../../components/ui/button/Button';
import FormModal, { FormField } from '../../components/common/FormModal';
import Badge from '../../components/ui/badge/Badge';
import { PlusIcon, BoltIcon, UserIcon, ShootingStarIcon, ImageIcon } from '../../icons';
export default function AuthorProfiles() {
const toast = useToast();
const [profiles, setProfiles] = useState<AuthorProfile[]>([]);
const [loading, setLoading] = useState(true);
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingProfile, setEditingProfile] = useState<AuthorProfile | null>(null);
const [formData, setFormData] = useState({
name: '',
description: '',
tone: '',
language: 'en',
is_active: true,
});
useEffect(() => {
loadProfiles();
}, []);
const loadProfiles = async () => {
try {
setLoading(true);
const response = await fetchAuthorProfiles();
setProfiles(response.results || []);
} catch (error: any) {
toast.error(`Failed to load author profiles: ${error.message}`);
} finally {
setLoading(false);
}
};
const handleCreate = () => {
setEditingProfile(null);
setFormData({
name: '',
description: '',
tone: '',
language: 'en',
is_active: true,
});
setIsModalOpen(true);
};
const handleEdit = (profile: AuthorProfile) => {
setEditingProfile(profile);
setFormData({
name: profile.name,
description: profile.description,
tone: profile.tone,
language: profile.language,
is_active: profile.is_active,
});
setIsModalOpen(true);
};
const handleSave = async () => {
try {
if (editingProfile) {
await updateAuthorProfile(editingProfile.id, formData);
toast.success('Author profile updated successfully');
} else {
await createAuthorProfile(formData);
toast.success('Author profile created successfully');
}
setIsModalOpen(false);
loadProfiles();
} catch (error: any) {
toast.error(`Failed to save: ${error.message}`);
}
};
const handleDelete = async (id: number) => {
if (!confirm('Are you sure you want to delete this author profile?')) return;
try {
await deleteAuthorProfile(id);
toast.success('Author profile deleted successfully');
loadProfiles();
} catch (error: any) {
toast.error(`Failed to delete: ${error.message}`);
}
};
const formFields: FormField[] = [
{ name: 'name', label: 'Name', type: 'text', required: true },
{ name: 'description', label: 'Description', type: 'textarea', required: false },
{ name: 'tone', label: 'Tone', type: 'text', required: true },
{ name: 'language', label: 'Language', type: 'text', required: true },
{ name: 'is_active', label: 'Active', type: 'checkbox', required: false },
];
// Thinker navigation tabs
const thinkerTabs = [
{ label: 'AI Instructions', path: '/thinker/prompts', icon: <BoltIcon /> },
{ label: 'Writing Voices', path: '/thinker/author-profiles', icon: <UserIcon /> },
{ label: 'Content Strategies', path: '/thinker/strategies', icon: <ShootingStarIcon /> },
{ label: 'Image Testing', path: '/thinker/image-testing', icon: <ImageIcon /> },
];
return (
<div className="p-6">
<PageMeta title="Author Profiles" />
<PageHeader
title="Choose Your Writing Voice"
badge={{ icon: <UserIcon />, color: 'blue' }}
navigation={<ModuleNavigationTabs tabs={thinkerTabs} />}
/>
<div className="mb-6 flex justify-between items-center">
<Button onClick={handleCreate} variant="primary">
<PlusIcon className="w-4 h-4 mr-2" />
Create Profile
</Button>
</div>
{loading ? (
<div className="flex items-center justify-center h-64">
<div className="text-gray-500">Loading...</div>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{profiles.map((profile) => (
<Card key={profile.id} className="p-6">
<div className="flex justify-between items-start mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">{profile.name}</h3>
<Badge variant="light" color={profile.is_active ? 'success' : 'dark'}>
{profile.is_active ? 'Active' : 'Inactive'}
</Badge>
</div>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">{profile.description}</p>
<div className="space-y-2 mb-4">
<div className="text-sm">
<span className="text-gray-500 dark:text-gray-400">Tone:</span>{' '}
<span className="text-gray-900 dark:text-white">{profile.tone}</span>
</div>
<div className="text-sm">
<span className="text-gray-500 dark:text-gray-400">Language:</span>{' '}
<span className="text-gray-900 dark:text-white">{profile.language}</span>
</div>
</div>
<div className="flex gap-2">
<Button variant="secondary" size="sm" onClick={() => handleEdit(profile)}>
Edit
</Button>
<Button variant="danger" size="sm" onClick={() => handleDelete(profile.id)}>
Delete
</Button>
</div>
</Card>
))}
</div>
)}
<FormModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onSave={handleSave}
title={editingProfile ? 'Edit Author Profile' : 'Create Author Profile'}
fields={formFields}
data={formData}
onChange={setFormData}
/>
</div>
);
}