feat: enhance privacy email viewer, dynamic pagination, and cinematic loading states

This commit is contained in:
idevakk
2026-03-04 22:31:32 +05:30
parent 011ca2a408
commit 22e2b2457a
3 changed files with 387 additions and 85 deletions

View File

@@ -21,6 +21,10 @@ class Mailbox extends Component
public $search = '';
public $viewMode = 'text'; // text | html
public $allowRemoteContent = false;
public $page = 1;
public $totalPages = 5;
@@ -38,16 +42,17 @@ class Mailbox extends Component
public function getEmailsProperty()
{
// Mock emails based on mailbox ID for demonstration
$emails = [
1 => [
// Mock emails based on mailbox ID
$baseEmails = [
1 => [ // Inbox
[
'id' => 1,
'from_name' => 'GitHub Security',
'from_email' => 'noreply@github.com',
'subject' => '[GitHub] A new personal access token was created',
'preview' => 'A new personal access token (classic) was recently added to your account.',
'content' => '<p>Hi @idevakk,</p><p>A new personal access token (classic) was recently added to your account IDEVAKK.</p><p>If this was you, you can safely ignore this email.</p><p>If this was not you, please visit https://github.com/settings/tokens to revoke the token.</p>',
'body_html' => '<p>Hi @idevakk,</p><p>A new personal access token (classic) was recently added to your account IDEVAKK.</p><p>If this was you, you can safely ignore this email.</p><p>If this was not you, please visit https://github.com/settings/tokens to revoke the token.</p>',
'body_text' => "Hi @idevakk,\n\nA new personal access token (classic) was recently added to your account IDEVAKK.\n\nIf this was you, you can safely ignore this email.\n\nIf this was not you, please visit https://github.com/settings/tokens to revoke the token.",
'time' => '10:24 AM',
'unread' => true,
'flagged' => true,
@@ -59,112 +64,131 @@ class Mailbox extends Component
'from_email' => 'updates@linear.app',
'subject' => 'New issue assigned: [UI-124] Fix sidebar overflow',
'preview' => 'You have been assigned to a new issue in the UI project. Please review the details...',
'content' => '<p>Hello,</p><p>You have been assigned to <strong>[UI-124] Fix sidebar overflow in mobile view</strong>.</p><p>Priority: High</p><p>Project: Imail Revamp</p><p>View details at https://linear.app/imail/issue/UI-124</p>',
'body_html' => '<p>Hello,</p><p>You have been assigned to <strong>[UI-124] Fix sidebar overflow in mobile view</strong>.</p><p>Priority: High</p><p>Project: Imail Revamp</p><p>View details at https://linear.app/imail/issue/UI-124</p>',
'body_text' => "Hello,\n\nYou have been assigned to [UI-124] Fix sidebar overflow in mobile view.\n\nPriority: High\nProject: Imail Revamp\n\nView details at https://linear.app/imail/issue/UI-124",
'time' => '11:45 AM',
'unread' => true,
'flagged' => false,
'attachments' => [],
],
[
'id' => 102,
'from_name' => 'Canva',
'from_email' => 'design@canva.com',
'subject' => 'Your design "Imail Presentation" is ready',
'preview' => 'Collaborate with your team on your latest design for the Imail product launch.',
'content' => '<p>Hey there!</p><p>Your team is waiting for your feedback on the <strong>Imail Presentation</strong> design.</p><p>Check the latest comments and approve the final version.</p>',
'time' => '9:12 AM',
'unread' => false,
'id' => 104,
'from_name' => 'Unsplash Updates',
'from_email' => 'hello@unsplash.com',
'subject' => 'Featured Photos: Cinematic Landscapes',
'preview' => 'Check out this week\'s curated collection of cinematic landscape photography...',
'body_html' => '<p>Hello Zemailer,</p><p>We have curated some new cinematic landscapes for your next project:</p><div style="margin: 20px 0;"><img src="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?auto=format&fit=crop&w=800&q=80" style="width: 100%; border-radius: 12px; margin-bottom: 15px;" alt="Mountain Landscape"><img src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?auto=format&fit=crop&w=800&q=80" style="width: 100%; border-radius: 12px;" alt="Lake Landscape"></div><p>Feel free to use them in your designs!</p>',
'body_text' => "Hello Zemailer,\n\nWe have curated some new cinematic landscapes for your next project.\n\n[Images are blocked by default in privacy mode]\n\nCheck them out on Unsplash!",
'time' => '7:45 AM',
'unread' => true,
'flagged' => false,
'attachments' => [
['name' => 'presentation_v1.pdf', 'size' => '4.2 MB'],
],
],
[
'id' => 103,
'from_name' => 'Figma',
'from_email' => 'notifications@figma.com',
'subject' => 'Atul Kumar mentioned you in "Mobile App (Draft)"',
'preview' => '"@idevakk take a look at the revised QR modal design, let me know if..."',
'content' => '<p><strong>Atul Kumar</strong> mentioned you in a comment on <strong>Mobile App (Draft)</strong>:</p><blockquote>"@idevakk take a look at the revised QR modal design, let me know if the proportions look right to you."</blockquote><p>Reply in Figma or view the comment online.</p>',
'time' => '8:30 AM',
'unread' => false,
'flagged' => true,
'attachments' => [],
],
// Generated Inbox items to reach 15
],
2 => [
2 => [ // Sent
[
'id' => 2,
'from_name' => 'Stripe',
'from_email' => 'support@stripe.com',
'subject' => 'Your weekly payment report',
'preview' => 'Your weekly report for the period of Feb 24 - Mar 2 is now available.',
'content' => '<p>Hello,</p><p>Your weekly report for the period of Feb 24 - Mar 2 is now available in your dashboard.</p><p>Total Volume: $12,450.00</p><p>View the full report details online.</p>',
'body_html' => '<p>Hello,</p><p>Your weekly report for the period of Feb 24 - Mar 2 is now available in your dashboard.</p><p>Total Volume: $12,450.00</p><p>View the full report details online.</p>',
'body_text' => "Hello,\n\nYour weekly report for the period of Feb 24 - Mar 2 is now available in your dashboard.\n\nTotal Volume: $12,450.00\n\nView the full report details online.",
'time' => 'Yesterday',
'unread' => false,
'flagged' => false,
'attachments' => [
['name' => 'report_mar_02.pdf', 'size' => '1.2 MB'],
],
'attachments' => [['name' => 'report_mar_02.pdf', 'size' => '1.2 MB']],
],
],
3 => [ // Notifications
[
'id' => 201,
'from_name' => 'Postmark',
'from_email' => 'alerts@postmarkapp.com',
'subject' => 'Outbound volume spike detected',
'preview' => 'We noticed a sudden increase in outbound emails from your "Production" server.',
'content' => '<p>Alert: Outbound volume spike.</p><p>Server: Production</p><p>We detected 5,000+ emails sent in the last hour. Please ensure this is expected activity.</p>',
'time' => 'Yesterday',
'id' => 3,
'from_name' => 'Slack',
'from_email' => 'notifications@slack.com',
'subject' => 'You have 12 unread messages from your team',
'preview' => 'Atul Kumar: "Did you check the new API endpoints? We need them for..."',
'body_html' => '<p>You have new activity in Slack.</p><ul><li><strong>#dev-chat</strong>: 8 new messages</li><li><strong>#announcements</strong>: 4 new messages</li></ul>',
'body_text' => "You have new activity in Slack.\n\n#dev-chat: 8 new messages\n#announcements: 4 new messages",
'time' => 'Mar 1',
'unread' => true,
'flagged' => false,
'attachments' => [],
],
[
'id' => 202,
'from_name' => 'Vercel',
'from_email' => 'deployments@vercel.com',
'subject' => 'Team "idevakk" deployment successful',
'preview' => 'Production deployment for the imail-frontend project has completed.',
'content' => '<p>Your deployment is live!</p><p>Project: imail-frontend</p><p>Command: <code>npm run build</code></p><p>View your deployment here: https://imail.app</p>',
'time' => 'Mar 2',
'unread' => false,
'flagged' => false,
'attachments' => [],
],
],
];
return $emails[$this->currentMailboxId] ?? [
[
'id' => 3,
'from_name' => 'Slack',
'from_email' => 'notifications@slack.com',
'subject' => 'You have 12 unread messages from your team',
'preview' => 'Atul Kumar: "Did you check the new API endpoints? We need them for..."',
'content' => '<p>You have new activity in Slack.</p><ul><li><strong>#dev-chat</strong>: 8 new messages</li><li><strong>#announcements</strong>: 4 new messages</li></ul>',
// Fill Inbox (MB 1) to 15
for ($i = 5; $i <= 18; $i++) {
$baseEmails[1][] = [
'id' => 1000 + $i,
'from_name' => "Partner $i",
'from_email' => "partner-$i@example.com",
'subject' => "Follow-up proposal #$i",
'preview' => "I wanted to check in regarding our previous discussion on project $i...",
'body_html' => "<p>Hello,</p><p>This is a follow-up email #$i regarding our partnership.</p>",
'body_text' => "Hello,\n\nThis is a follow-up email #$i regarding our partnership.",
'time' => 'Mar 1',
'unread' => true,
'flagged' => false,
'unread' => $i % 3 === 0,
'flagged' => $i % 5 === 0,
'attachments' => [],
],
[
'id' => 301,
'from_name' => 'Zoom',
'from_email' => 'no-reply@zoom.us',
'subject' => 'Meeting Reminder: "Sprint Planning"',
'preview' => 'Your Sprint Planning meeting is scheduled to start in 15 minutes.',
'content' => '<p>Friendly reminder that your Sprint Planning call starts soon.</p><p>Link: https://zoom.us/j/123456789</p>',
'time' => 'Feb 28',
];
}
// Fill Sent (MB 2) to 15
for ($i = 1; $i <= 14; $i++) {
$baseEmails[2][] = [
'id' => 2000 + $i,
'from_name' => 'Me',
'from_email' => 'idevakk@imail.com',
'subject' => "Re: Project Sync $i",
'preview' => "Sounds good, let's proceed with the plan we discussed for sprint $i.",
'body_html' => "<p>Hi team,</p><p>Update on project $i: everything is on track.</p>",
'body_text' => "Hi team,\n\nUpdate on project $i: everything is on track.",
'time' => 'Feb 26',
'unread' => false,
'flagged' => $i % 4 === 0,
'attachments' => [],
];
}
// Fill Others (MB 3) to 15
for ($i = 1; $i <= 14; $i++) {
$baseEmails[3][] = [
'id' => 3000 + $i,
'from_name' => "System Notification $i",
'from_email' => 'noreply@system.com',
'subject' => "Security Alert $i: New Login",
'preview' => "We detected a new login to your account from a new device on day $i...",
'body_html' => "<p>A new login was detected on your account.</p><p>Location: City $i</p>",
'body_text' => "A new login was detected on your account.\n\nLocation: City $i",
'time' => 'Feb 25',
'unread' => $i % 2 === 0,
'flagged' => false,
'attachments' => [],
],
];
];
}
$allData = $baseEmails[$this->currentMailboxId] ?? $baseEmails[3];
$total = count($allData);
$this->totalPages = ceil($total / 10);
// Ensure page is within bounds
if ($this->page > $this->totalPages && $this->totalPages > 0) {
$this->page = $this->totalPages;
}
return array_slice($allData, ($this->page - 1) * 10, 10);
}
public function selectEmail($id)
{
$this->selectedEmailId = $id;
$this->viewMode = 'text';
$this->allowRemoteContent = false;
// Simulate cinematic loading
usleep(500000); // 500ms
}
public function switchMailbox($id)
@@ -172,6 +196,7 @@ class Mailbox extends Component
$this->currentMailboxId = $id;
$this->selectedEmailId = null;
$this->search = '';
$this->page = 1;
}
public function createMailbox()
@@ -226,6 +251,7 @@ class Mailbox extends Component
{
if ($this->page < $this->totalPages) {
$this->page++;
$this->selectedEmailId = null;
}
}
@@ -233,6 +259,7 @@ class Mailbox extends Component
{
if ($this->page > 1) {
$this->page--;
$this->selectedEmailId = null;
}
}
@@ -243,6 +270,29 @@ class Mailbox extends Component
$this->dispatch('qrCodeGenerated', address: $address);
}
public function getProcessedContent($email)
{
$content = $email['body_html'];
$isText = $this->viewMode === 'text';
// Fallback to HTML if text is selected but body_text is empty
if ($isText && ! empty($email['body_text'])) {
return trim(e($email['body_text']));
}
if ($isText) {
// If fallback occurred, we sanitize the HTML to text
return trim(strip_tags($content));
}
if (! $this->allowRemoteContent) {
// Block remote assets by replacing src with data-src for img tags
return preg_replace('/<img\s[^>]*?\bsrc\s*=\s*([\'"])(.*?)\1/i', '<img $2 data-blocked-src=$1$2$1 src="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 1 1\'%3E%3C/svg%3E" class="blocked-remote-asset shadow-sm border border-white/5 opacity-50"', $content);
}
return $content;
}
public function render()
{
$currentMailbox = collect($this->activeMailboxes)->firstWhere('id', $this->currentMailboxId);