trypost/lang/en/settings.php
Paulo Castellano 3c3b170b21 feat: @mentions in comments, AI Action layer + MCP tools, settings tabs
Mentions in post comments
- @mention autocomplete (workspace members, current user excluded) with
  marker syntax @[uuid] persisted, display names rendered via CommentBody
  chips; live edit replaces markers with names and converts back on save.
- NotifyMentions action with workspace-scoped membership check, dedupes
  same user, only newly-added mentions on update.
- Email + in-app via SendNotification job, respecting per-user
  notification_preferences.mentioned_in_comment.
- Heartbeat-based presence (Cache, 60s TTL, 30s ping) so online recipients
  get only the in-app notification — no email noise.
- Real-time bell on workspace.{id}.user.{id} private channel
  (NotificationCreated event), scoped channel name avoids client-side
  filtering and lays out a convention for future workspace channels.
- Mailable localized via lang/{en,es,pt-BR}/mail.php; Maizzle source
  template for the email is committed and built into resources/views/mail.

AI generation refactor (Action layer + MCP)
- Extracted Actions/Ai/Generate{Image,Video} with QuotaExhaustedException
  so agent tools and MCP tools share a single domain entry point.
- Mcp/Tools/Ai/Generate{Image,Video}Tool registered in TryPostServer; both
  return MediaResource payloads.
- Orientation::imageApiSize maps non-OpenAI ratios to 1:1/2:3/3:2.
- config/ai.php is now the single source of truth driven by env, removing
  the trypost.ai shim. Default text/image providers flipped to OpenAI.

Settings/UX
- /settings/workspace split into shadcn Tabs (Workspace / Brand / Users)
  with three components.
- /assets and the in-editor MediaPicker open the ImagePreviewDialog
  lightbox on image click while preserving action button behaviour.
- Comments tab landed via ?tab=comments&comment=<id> from notification
  click (scroll-to + temporary highlight).
- Mention autocomplete popover flips above when near the viewport bottom.
- Real social platform PNGs replace Tabler brand glyphs in schedule
  pills and post list, with hover tooltip carrying display_name + handle.

Bug fixes
- AcceptInvite: controller now passes workspace + role payload that the
  Vue page expects; login/register CTAs preselect the invite email.
- WorkspaceInvite mailable: stopped referencing nonexistent
  $invite->workspace and $invite->role; column added to the migration,
  Invite model casts role to WorkspaceRole, CreateInvite persists it.
- PostCommentCreated: added broadcastAs so .PostCommentCreated actually
  matches the Echo listener; payload now includes mentioned_users so
  receivers render the chip correctly without a refetch.
- Preview components for X/Pinterest/Threads/Bluesky/LinkedIn/Mastodon/
  TikTok/YouTube switched from item.type === 'image' to
  !isVideoMedia(item) so media without a persisted type still renders.
- UpdatePostRequest now accepts media.*.{type,mime_type,size,...} so the
  posts.media JSON keeps the metadata that the previews need.
- Removed throttle:6,1 from social connect routes (was 429ing legitimate
  OAuth retries).
- Used MediaType enum cases instead of literal 'image'/'video' strings
  when creating media rows.

Tests
- MentionParser unit tests, NotifyMentions feature tests including
  online/offline channel selection and preference gating, MCP AI tool
  happy paths, MentionedInComment mailable rendering, AcceptInvite +
  search-members + index mentioned_users path. 1229 passing.
2026-05-01 20:59:03 -03:00

244 lines
9.7 KiB
PHP

<?php
return [
'title' => 'Settings',
'description' => 'Manage your profile and account settings',
'nav' => [
'profile' => 'Profile',
'password' => 'Password',
'workspace' => 'Workspace',
'members' => 'Members',
'notifications' => 'Notifications',
'billing' => 'Billing',
],
'notifications' => [
'title' => 'Notification preferences',
'heading' => 'Email notifications',
'description' => 'Choose which email notifications you want to receive',
'post_published' => 'Post published',
'post_published_description' => 'Receive an email when your post is published successfully',
'post_failed' => 'Post failed',
'post_failed_description' => 'Receive an email when your post fails to publish',
'account_disconnected' => 'Account disconnected',
'account_disconnected_description' => 'Receive an email when a social account is disconnected',
'save' => 'Save preferences',
],
'profile' => [
'title' => 'Profile settings',
'photo_heading' => 'Profile photo',
'photo_description' => 'Upload a profile photo',
'heading' => 'Profile information',
'description' => 'Update your name and email address',
'avatar' => 'Avatar',
'name' => 'Name',
'name_placeholder' => 'Full name',
'email' => 'Email address',
'email_placeholder' => 'Email address',
'email_unverified' => 'Your email address is unverified.',
'resend_verification' => 'Click here to resend the verification email.',
'verification_sent' => 'A new verification link has been sent to your email address.',
'save' => 'Save',
],
'password' => [
'title' => 'Password settings',
'heading' => 'Update password',
'description' => 'Ensure your account is using a long, random password to stay secure',
'current_password' => 'Current password',
'current_password_placeholder' => 'Current password',
'new_password' => 'New password',
'new_password_placeholder' => 'New password',
'confirm_password' => 'Confirm password',
'confirm_password_placeholder' => 'Confirm password',
'save' => 'Save password',
],
'delete_account' => [
'heading' => 'Delete account',
'description' => 'Delete your account and all of its resources',
'warning' => 'Warning',
'warning_message' => 'Please proceed with caution, this cannot be undone.',
'button' => 'Delete account',
'modal_title' => 'Are you sure you want to delete your account?',
'modal_description' => 'Once your account is deleted, all of its resources and data will also be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.',
'password' => 'Password',
'password_placeholder' => 'Password',
'cancel' => 'Cancel',
'confirm' => 'Delete account',
],
'workspace' => [
'tabs' => [
'workspace' => 'Workspace',
'brand' => 'Brand',
'users' => 'Users',
],
'title' => 'Workspace settings',
'logo_heading' => 'Workspace logo',
'logo_description' => 'Upload a logo for your workspace',
'heading' => 'Workspace name',
'description' => 'Update your workspace name',
'members_heading' => 'Members',
'members_description' => 'Manage workspace members and invitations',
'name' => 'Name',
'name_placeholder' => 'My Workspace',
'save' => 'Save',
],
'brand' => [
'title' => 'Brand',
'description' => 'Configure your brand identity for AI-generated content.',
'website' => 'Website',
'website_placeholder' => 'https://yourbrand.com',
'brand_description' => 'Description',
'brand_description_placeholder' => 'Tell us about your brand, what you do, and who your audience is...',
'tone' => 'Tone of voice',
'tone_professional' => 'Professional',
'tone_casual' => 'Casual',
'tone_friendly' => 'Friendly',
'tone_bold' => 'Bold',
'tone_inspirational' => 'Inspirational',
'tone_humorous' => 'Humorous',
'tone_educational' => 'Educational',
'voice_notes' => 'Voice notes',
'voice_notes_placeholder' => 'Additional writing guidelines, words to avoid, style preferences...',
'content_language' => 'Content language',
'content_language_description' => 'Language used for AI-generated captions, hashtags, and any text inside generated images or videos.',
],
'members' => [
'title' => 'Members',
'heading' => 'Team members',
'description' => 'Manage members and invites for this workspace',
'cancel' => 'Cancel',
'remove' => 'Remove',
'make_admin' => 'Make admin',
'make_member' => 'Make member',
'invite' => [
'title' => 'Invite Member',
'description' => 'Send an email invite to add collaborators',
'email' => 'Email',
'email_placeholder' => 'collaborator@email.com',
'role' => 'Role',
'role_placeholder' => 'Select a role',
'submit' => 'Send Invite',
],
'pending' => [
'title' => 'Pending Invites',
'description' => 'Invites awaiting acceptance',
'empty' => 'No pending invites',
],
'list' => [
'title' => 'Members',
'description' => 'People with access to this workspace',
'empty' => 'No members besides the owner',
],
'remove_modal' => [
'title' => 'Remove member',
'description' => 'Are you sure you want to remove this member from the workspace? They will lose access to all workspace resources.',
'action' => 'Remove member',
],
'cancel_invite_modal' => [
'title' => 'Cancel invitation',
'description' => 'Are you sure you want to cancel this invitation?',
'action' => 'Cancel invitation',
],
'roles' => [
'owner' => 'Owner',
'admin' => 'Admin',
'member' => 'Member',
'viewer' => 'Viewer',
],
'flash' => [
'invite_sent' => 'Invite sent successfully!',
'invite_deleted' => 'Invite deleted.',
'member_removed' => 'Member removed successfully.',
'role_updated' => 'Member role updated.',
'wrong_email' => 'This invite is for a different email address.',
'already_member' => 'You are already a member of this workspace.',
'invite_accepted' => 'Welcome! You are now a member of the workspace.',
'invite_declined' => 'Invite declined.',
],
],
'account' => [
'title' => 'Account Settings',
'description' => 'Manage your account name and billing email',
'name' => 'Account Name',
'name_placeholder' => 'My Company',
'billing_email' => 'Billing Email',
'billing_email_placeholder' => 'billing@company.com',
'billing_email_hint' => 'This email will be used for invoices and billing communications from Stripe.',
'submit' => 'Save',
],
'flash' => [
'account_updated' => 'Account updated successfully!',
'profile_updated' => 'Profile updated successfully!',
'language_updated' => 'Language updated successfully!',
'password_updated' => 'Password updated successfully!',
'workspace_updated' => 'Settings updated successfully!',
'photo_updated' => 'Photo updated successfully!',
'photo_deleted' => 'Photo removed successfully!',
'logo_updated' => 'Logo uploaded successfully!',
'logo_deleted' => 'Logo removed successfully!',
'notifications_updated' => 'Notification preferences updated!',
],
'api_keys' => [
'title' => 'API Keys',
'page_title' => 'API Keys',
'heading' => 'API Keys',
'description' => 'Manage API keys for programmatic access to your workspace.',
'create' => 'Create API Key',
'copy' => 'Copy',
'new_token_message' => 'Your new API key has been created. Copy it now — you won\'t be able to see it again.',
'table' => [
'name' => 'Name',
'key' => 'Key',
'status' => 'Status',
'expires' => 'Expires',
'last_used' => 'Last Used',
'never' => 'Never',
],
'actions' => [
'copy_id' => 'Copy API Key ID',
'copy_id_success' => 'API Key ID copied to clipboard',
'delete' => 'Delete',
],
'empty' => [
'title' => 'No API keys yet',
'description' => 'Create an API key to access your workspace programmatically.',
],
'delete_modal' => [
'title' => 'Delete API key',
'description' => 'Are you sure you want to delete this API key? Any applications using this key will lose access immediately.',
'action' => 'Delete API key',
],
'create_dialog' => [
'title' => 'Create API Key',
'description' => 'Create a new API key for programmatic access to your workspace.',
'name' => 'Name',
'name_placeholder' => 'e.g. Production API Key',
'expires' => 'Expiration date (optional)',
'expires_placeholder' => 'No expiration',
'submit' => 'Create',
'cancel' => 'Cancel',
],
'flash' => [
'created' => 'API key created successfully!',
'deleted' => 'API key deleted successfully!',
],
],
];