diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json
index 6c9859d..de89f5b 100644
--- a/assets/i18n/en-US.json
+++ b/assets/i18n/en-US.json
@@ -314,7 +314,7 @@
   "accountSettingsHelpContent": "This page allows you to manage your account security, privacy, and other settings. If you need assistance, please contact support.",
   "unauthorized": "Unauthorized",
   "unauthorizedHint": "You're not signed in or session expired, please sign in again.",
-  "publisherVisitAccountPage": "Visit the profile of {}",
+  "publisherBelongsTo": "Belongs to {}",
   "postVisibility": "Visibility",
   "postVisibilityPublic": "Public",
   "postVisibilityFriends": "Friends Only",
@@ -424,5 +424,6 @@
   "checkInResultT1": "Poor",
   "checkInResultT2": "Mid",
   "checkInResultT3": "Good",
-  "checkInResultT4": "Best"
+  "checkInResultT4": "Best",
+  "accountProfileView": "View Profile"
 }
diff --git a/lib/route.gr.dart b/lib/route.gr.dart
index b6047bd..6d630be 100644
--- a/lib/route.gr.dart
+++ b/lib/route.gr.dart
@@ -15,7 +15,7 @@ import 'package:flutter/material.dart' as _i28;
 import 'package:island/models/post.dart' as _i30;
 import 'package:island/route.dart' as _i31;
 import 'package:island/screens/account.dart' as _i2;
-import 'package:island/screens/account/me/event_calendar.dart' as _i14;
+import 'package:island/screens/account/event_calendar.dart' as _i14;
 import 'package:island/screens/account/me/settings.dart' as _i3;
 import 'package:island/screens/account/me/update.dart' as _i25;
 import 'package:island/screens/account/profile.dart' as _i1;
diff --git a/lib/screens/account/me/event_calendar.dart b/lib/screens/account/event_calendar.dart
similarity index 65%
rename from lib/screens/account/me/event_calendar.dart
rename to lib/screens/account/event_calendar.dart
index fa8181e..65b1234 100644
--- a/lib/screens/account/me/event_calendar.dart
+++ b/lib/screens/account/event_calendar.dart
@@ -6,6 +6,7 @@ import 'package:gap/gap.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:island/pods/event_calendar.dart';
 import 'package:island/screens/account/profile.dart';
+import 'package:island/widgets/account/account_nameplate.dart';
 import 'package:island/widgets/app_scaffold.dart';
 import 'package:island/widgets/content/cloud_files.dart';
 import 'package:island/widgets/account/event_calendar.dart';
@@ -86,29 +87,7 @@ class EventCalanderScreen extends HookConsumerWidget {
 
                       // Show user profile if viewing someone else's calendar
                       if (name != 'me' && user.hasValue)
-                        Container(
-                          decoration: BoxDecoration(
-                            border: Border.all(
-                              width:
-                                  1 / MediaQuery.of(context).devicePixelRatio,
-                              color: Theme.of(context).dividerColor,
-                            ),
-                            borderRadius: BorderRadius.all(Radius.circular(8)),
-                          ),
-                          margin: EdgeInsets.all(16),
-                          child: Card(
-                            margin: EdgeInsets.zero,
-                            elevation: 0,
-                            color: Colors.transparent,
-                            child: ListTile(
-                              leading: ProfilePictureWidget(
-                                fileId: user.value!.profile.picture?.id,
-                              ),
-                              title: Text(user.value!.nick).bold(),
-                              subtitle: Text('@${user.value!.name}'),
-                            ),
-                          ),
-                        ),
+                        AccountNameplate(name: name),
                     ],
                   ),
                 ).center()
@@ -132,28 +111,8 @@ class EventCalanderScreen extends HookConsumerWidget {
 
                     // Show user profile if viewing someone else's calendar
                     if (name != 'me' && user.hasValue)
-                      Container(
-                        decoration: BoxDecoration(
-                          border: Border.all(
-                            width: 1 / MediaQuery.of(context).devicePixelRatio,
-                            color: Theme.of(context).dividerColor,
-                          ),
-                          borderRadius: BorderRadius.all(Radius.circular(8)),
-                        ),
-                        margin: EdgeInsets.all(16),
-                        child: Card(
-                          margin: EdgeInsets.zero,
-                          elevation: 0,
-                          color: Colors.transparent,
-                          child: ListTile(
-                            leading: ProfilePictureWidget(
-                              fileId: user.value!.profile.picture?.id,
-                            ),
-                            title: Text(user.value!.nick).bold(),
-                            subtitle: Text('@${user.value!.name}'),
-                          ),
-                        ),
-                      ),
+                      AccountNameplate(name: name),
+                    Gap(MediaQuery.of(context).padding.bottom + 16),
                   ],
                 ),
       ),
diff --git a/lib/screens/account/profile.dart b/lib/screens/account/profile.dart
index a26cf6b..e35e6d2 100644
--- a/lib/screens/account/profile.dart
+++ b/lib/screens/account/profile.dart
@@ -5,11 +5,13 @@ import 'package:gap/gap.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:island/models/user.dart';
 import 'package:island/pods/config.dart';
+import 'package:island/pods/event_calendar.dart';
 import 'package:island/pods/network.dart';
 import 'package:island/pods/userinfo.dart';
 import 'package:island/services/color.dart';
 import 'package:island/widgets/account/account_name.dart';
 import 'package:island/widgets/account/badge.dart';
+import 'package:island/widgets/account/fortune_graph.dart';
 import 'package:island/widgets/account/leveling_progress.dart';
 import 'package:island/widgets/account/status.dart';
 import 'package:island/widgets/app_scaffold.dart';
@@ -67,7 +69,14 @@ class AccountProfileScreen extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
+    final now = DateTime.now();
+
     final account = ref.watch(accountProvider(name));
+    final accountEvents = ref.watch(
+      eventCalendarProvider(
+        EventCalendarQuery(uname: name, year: now.year, month: now.month),
+      ),
+    );
     final appbarColor = ref.watch(accountAppbarForcegroundColorProvider(name));
 
     final appbarShadow = Shadow(
@@ -173,22 +182,39 @@ class AccountProfileScreen extends HookConsumerWidget {
                           mark: data.profile.verification!,
                         ),
                     ],
-                  ).padding(horizontal: 20, bottom: 24),
+                  ).padding(horizontal: 20),
                 ),
 
                 SliverToBoxAdapter(
-                  child: const Divider(height: 1).padding(bottom: 24),
+                  child: const Divider(height: 1).padding(vertical: 24),
+                ),
+                SliverToBoxAdapter(
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.stretch,
+                    children: [
+                      Text('bio').tr().bold(),
+                      Text(
+                        data.profile.bio.isEmpty
+                            ? 'descriptionNone'.tr()
+                            : data.profile.bio,
+                      ),
+                    ],
+                  ).padding(horizontal: 24),
+                ),
+
+                SliverToBoxAdapter(
+                  child: const Divider(height: 1).padding(top: 24),
+                ),
+                SliverToBoxAdapter(
+                  child: Column(
+                    children: [
+                      FortuneGraphWidget(
+                        events: accountEvents,
+                        eventCalanderUser: data.name,
+                      ),
+                    ],
+                  ).padding(all: 8),
                 ),
-                if (data.profile.bio.isNotEmpty)
-                  SliverToBoxAdapter(
-                    child: Column(
-                      crossAxisAlignment: CrossAxisAlignment.stretch,
-                      children: [
-                        Text('bio').tr().bold(),
-                        Text(data.profile.bio),
-                      ],
-                    ).padding(horizontal: 24),
-                  ),
               ],
             ),
           ),
diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart
index 62e8de3..81cd554 100644
--- a/lib/screens/chat/room.dart
+++ b/lib/screens/chat/room.dart
@@ -385,6 +385,7 @@ class ChatRoomScreen extends HookConsumerWidget {
         if (['messages.read'].contains(pkt.type)) return;
 
         if (pkt.type == 'messages.typing' && pkt.data?['sender'] != null) {
+          if (pkt.data?['room_id'] != chatRoom.value?.id) return;
           if (pkt.data?['sender_id'] == chatIdentity.value?.id) return;
 
           final sender = SnChatMember.fromJson(
diff --git a/lib/screens/posts/pub_profile.dart b/lib/screens/posts/pub_profile.dart
index af3bf4c..fabe2fd 100644
--- a/lib/screens/posts/pub_profile.dart
+++ b/lib/screens/posts/pub_profile.dart
@@ -17,6 +17,7 @@ import 'package:island/widgets/alert.dart';
 import 'package:island/widgets/app_scaffold.dart';
 import 'package:island/widgets/content/cloud_files.dart';
 import 'package:island/widgets/post/post_list.dart';
+import 'package:material_symbols_icons/symbols.dart';
 import 'package:palette_generator/palette_generator.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:styled_widget/styled_widget.dart';
@@ -210,65 +211,85 @@ class PublisherProfileScreen extends HookConsumerWidget {
                               spacing: 6,
                               children: [
                                 Text(data.nick).fontSize(20),
+                                if (data.verification != null)
+                                  VerificationMark(mark: data.verification!),
                                 Text(
                                   '@${data.name}',
                                 ).fontSize(14).opacity(0.85),
                               ],
                             ),
                             if (data.type == 0 && data.account != null)
-                              InkWell(
-                                onTap: () {
-                                  context.router.pushPath(
-                                    '/account/${data.account!.name}',
-                                  );
-                                },
-                                child: Row(
-                                  crossAxisAlignment: CrossAxisAlignment.center,
-                                  spacing: 4,
-                                  children: [
-                                    Text(
-                                      'publisherVisitAccountPage'.tr(
-                                        args: ['@${data.account!.name}'],
-                                      ),
-                                    ).fontSize(14),
-                                    Icon(Icons.launch, size: 14),
-                                  ],
-                                ).opacity(0.85),
-                              ).padding(bottom: 6),
+                              Row(
+                                crossAxisAlignment: CrossAxisAlignment.center,
+                                spacing: 6,
+                                children: [
+                                  Icon(
+                                    data.type == 0
+                                        ? Symbols.person
+                                        : Symbols.workspaces,
+                                    fill: 1,
+                                    size: 17,
+                                  ),
+                                  Text(
+                                    'publisherBelongsTo'.tr(
+                                      args: ['@${data.account!.name}'],
+                                    ),
+                                  ).fontSize(14),
+                                ],
+                              ).opacity(0.85).padding(bottom: 6),
                             if (data.type == 0 && data.account != null)
                               AccountStatusWidget(
                                 uname: data.account!.name,
                                 padding: EdgeInsets.zero,
                               ),
+                            OutlinedButton.icon(
+                              onPressed: () {
+                                Navigator.pop(context);
+                                context.router.pushPath(
+                                  '/account/${data.name}',
+                                );
+                              },
+                              icon: const Icon(Symbols.launch),
+                              label: Text('accountProfileView').tr(),
+                              style: ButtonStyle(
+                                visualDensity: VisualDensity(vertical: -2),
+                              ),
+                            ).padding(top: 8),
                           ],
                         ),
                       ),
                     ],
-                  ).padding(horizontal: 24, top: 24, bottom: 24),
+                  ).padding(horizontal: 24, top: 24),
                 ),
                 SliverToBoxAdapter(
                   child: Column(
-                    spacing: 24,
                     children: [
                       if (badges.value?.isNotEmpty ?? false)
-                        BadgeList(badges: badges.value!),
+                        BadgeList(badges: badges.value!).padding(top: 16),
                       if (data.verification != null)
-                        VerificationStatusCard(mark: data.verification!),
+                        VerificationStatusCard(
+                          mark: data.verification!,
+                        ).padding(top: 16),
                     ],
-                  ).padding(horizontal: 24, bottom: 24),
+                  ).padding(horizontal: 24),
+                ),
+                SliverToBoxAdapter(
+                  child: const Divider(height: 1).padding(vertical: 24),
+                ),
+                SliverToBoxAdapter(
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.stretch,
+                    children: [
+                      Text('bio').tr().bold(),
+                      Text(
+                        data.bio.isEmpty ? 'descriptionNone'.tr() : data.bio,
+                      ),
+                    ],
+                  ).padding(horizontal: 24),
+                ),
+                SliverToBoxAdapter(
+                  child: const Divider(height: 1).padding(top: 24),
                 ),
-                SliverToBoxAdapter(child: const Divider(height: 1)),
-                if (data.bio.isNotEmpty)
-                  SliverToBoxAdapter(
-                    child: Column(
-                      crossAxisAlignment: CrossAxisAlignment.stretch,
-                      children: [Text('bio').tr().bold(), Text(data.bio)],
-                    ).padding(horizontal: 24, top: 24),
-                  ),
-                if (data.bio.isNotEmpty)
-                  SliverToBoxAdapter(
-                    child: const Divider(height: 1).padding(top: 24),
-                  ),
                 SliverPostList(pubName: name),
                 SliverGap(MediaQuery.of(context).padding.bottom + 16),
               ],
diff --git a/lib/services/time.dart b/lib/services/time.dart
index 31bd462..6e61381 100644
--- a/lib/services/time.dart
+++ b/lib/services/time.dart
@@ -1,3 +1,7 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/widgets.dart';
+import 'package:relative_time/relative_time.dart';
+
 extension DurationFormatter on Duration {
   String formatDuration() {
     final isNegative = inMicroseconds < 0;
@@ -16,3 +20,21 @@ extension DurationFormatter on Duration {
     return '${isNegative ? '-' : ''}$hours:$minutes:$seconds';
   }
 }
+
+extension DateTimeFormatter on DateTime {
+  String formatSystem() {
+    return DateFormat.yMd().add_jm().format(toLocal());
+  }
+
+  String formatCustom(String pattern) {
+    return DateFormat(pattern).format(toLocal());
+  }
+
+  String formatWithLocale(String locale) {
+    return DateFormat.yMd().add_jm().format(toLocal()).toString();
+  }
+
+  String formatRelative(BuildContext context) {
+    return RelativeTime(context).format(toLocal());
+  }
+}
diff --git a/lib/widgets/account/account_nameplate.dart b/lib/widgets/account/account_nameplate.dart
new file mode 100644
index 0000000..b125e96
--- /dev/null
+++ b/lib/widgets/account/account_nameplate.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:island/screens/account/profile.dart';
+import 'package:island/widgets/content/cloud_files.dart';
+import 'package:styled_widget/styled_widget.dart';
+import 'package:easy_localization/easy_localization.dart';
+
+class AccountNameplate extends HookConsumerWidget {
+  final String name;
+  const AccountNameplate({super.key, required this.name});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final user = ref.watch(accountProvider(name));
+
+    return Container(
+      decoration: BoxDecoration(
+        border: Border.all(
+          width: 1 / MediaQuery.of(context).devicePixelRatio,
+          color: Theme.of(context).dividerColor,
+        ),
+        borderRadius: BorderRadius.all(Radius.circular(8)),
+      ),
+      margin: EdgeInsets.all(16),
+      child: Card(
+        margin: EdgeInsets.zero,
+        elevation: 0,
+        color: Colors.transparent,
+        child: user.when(
+          data: (account) => ListTile(
+            leading: ProfilePictureWidget(
+              fileId: account.profile.picture?.id,
+            ),
+            title: Text(account.nick).bold(),
+            subtitle: Text('@${account.name}'),
+          ),
+          loading: () => ListTile(
+            leading: const CircularProgressIndicator(),
+            title: const Text('loading').bold().tr(),
+            subtitle: const Text('...'),
+          ),
+          error: (error, stackTrace) => ListTile(
+            leading: Icon(Icons.error_outline, color: Colors.red),
+            title: Text('somethingWentWrong').bold().tr(),
+            subtitle: Text(error.toString()),
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/widgets/account/account_pfc.dart b/lib/widgets/account/account_pfc.dart
index 5c5c88a..14b1129 100644
--- a/lib/widgets/account/account_pfc.dart
+++ b/lib/widgets/account/account_pfc.dart
@@ -1,5 +1,6 @@
 import 'dart:math' as math;
 
+import 'package:auto_route/auto_route.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_popup_card/flutter_popup_card.dart';
@@ -12,6 +13,7 @@ import 'package:island/widgets/account/leveling_progress.dart';
 import 'package:island/widgets/account/status.dart';
 import 'package:island/widgets/content/cloud_files.dart';
 import 'package:island/widgets/response.dart';
+import 'package:material_symbols_icons/symbols.dart';
 import 'package:styled_widget/styled_widget.dart';
 
 class AccountProfileCard extends HookConsumerWidget {
@@ -34,17 +36,18 @@ class AccountProfileCard extends HookConsumerWidget {
                 mainAxisSize: MainAxisSize.min,
                 crossAxisAlignment: CrossAxisAlignment.stretch,
                 children: [
-                  ClipRRect(
-                    borderRadius: const BorderRadius.vertical(
-                      top: Radius.circular(12),
+                  if (data.profile.background != null)
+                    ClipRRect(
+                      borderRadius: const BorderRadius.vertical(
+                        top: Radius.circular(12),
+                      ),
+                      child: AspectRatio(
+                        aspectRatio: 16 / 9,
+                        child: CloudImageWidget(file: data.profile.background),
+                      ),
                     ),
-                    child: AspectRatio(
-                      aspectRatio: 16 / 9,
-                      child: CloudImageWidget(file: data.profile.background),
-                    ),
-                  ),
                   Column(
-                    crossAxisAlignment: CrossAxisAlignment.start,
+                    crossAxisAlignment: CrossAxisAlignment.stretch,
                     children: [
                       Row(
                         children: [
@@ -76,6 +79,14 @@ class AccountProfileCard extends HookConsumerWidget {
                         experience: data.profile.experience,
                         progress: data.profile.levelingProgress,
                       ).padding(top: 12),
+                      FilledButton.tonalIcon(
+                        onPressed: () {
+                          Navigator.pop(context);
+                          context.router.pushPath('/account/${data.name}');
+                        },
+                        icon: const Icon(Symbols.launch),
+                        label: Text('accountProfileView').tr(),
+                      ).padding(top: 12, horizontal: 2),
                     ],
                   ).padding(horizontal: 24, vertical: 16),
                 ],
@@ -86,9 +97,14 @@ class AccountProfileCard extends HookConsumerWidget {
                 onRetry: () => ref.invalidate(accountProvider(uname)),
               ),
           loading:
-              () => Padding(
-                padding: const EdgeInsets.all(24),
-                child: CircularProgressIndicator(),
+              () => SizedBox(
+                width: width,
+                height: width,
+                child:
+                    Padding(
+                      padding: const EdgeInsets.all(24),
+                      child: CircularProgressIndicator(),
+                    ).center(),
               ),
         ),
       ),
diff --git a/lib/widgets/account/fortune_graph.dart b/lib/widgets/account/fortune_graph.dart
index 46da9ea..26f9704 100644
--- a/lib/widgets/account/fortune_graph.dart
+++ b/lib/widgets/account/fortune_graph.dart
@@ -1,3 +1,4 @@
+import 'package:auto_route/auto_route.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:fl_chart/fl_chart.dart';
 import 'package:flutter/material.dart';
@@ -23,6 +24,8 @@ class FortuneGraphWidget extends HookConsumerWidget {
   /// Callback when a point is selected
   final void Function(DateTime)? onPointSelected;
 
+  final String? eventCalanderUser;
+
   const FortuneGraphWidget({
     super.key,
     required this.events,
@@ -30,6 +33,7 @@ class FortuneGraphWidget extends HookConsumerWidget {
     this.maxWidth = double.infinity,
     this.height = 180,
     this.onPointSelected,
+    this.eventCalanderUser,
   });
 
   @override
@@ -48,9 +52,27 @@ class FortuneGraphWidget extends HookConsumerWidget {
     final content = Column(
       crossAxisAlignment: CrossAxisAlignment.stretch,
       children: [
-        Text(
-          'fortuneGraph',
-        ).tr().fontSize(18).bold().padding(all: 16, bottom: 24),
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          children: [
+            Text('fortuneGraph').tr().fontSize(18).bold(),
+            if (eventCalanderUser != null)
+              IconButton(
+                icon: const Icon(Icons.calendar_month, size: 20),
+                visualDensity: const VisualDensity(
+                  horizontal: -4,
+                  vertical: -4,
+                ),
+                padding: EdgeInsets.zero,
+                constraints: const BoxConstraints(),
+                onPressed: () {
+                  context.router.pushNamed(
+                    '/account/$eventCalanderUser/calendar',
+                  );
+                },
+              ),
+          ],
+        ).padding(all: 16, bottom: 24),
         SizedBox(
           height: height,
           child: filteredEvents.when(
@@ -75,7 +97,7 @@ class FortuneGraphWidget extends HookConsumerWidget {
               final maxDate = data.last.date;
 
               return Padding(
-                padding: const EdgeInsets.fromLTRB(16, 0, 16, 24),
+                padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
                 child: LineChart(
                   LineChartData(
                     gridData: FlGridData(
diff --git a/lib/widgets/account/status.dart b/lib/widgets/account/status.dart
index 901de5a..31c15f7 100644
--- a/lib/widgets/account/status.dart
+++ b/lib/widgets/account/status.dart
@@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:island/models/user.dart';
 import 'package:island/pods/network.dart';
+import 'package:island/screens/account/profile.dart';
+import 'package:island/services/time.dart';
 import 'package:island/widgets/account/status_creation.dart';
 import 'package:material_symbols_icons/symbols.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -104,14 +106,15 @@ class AccountStatusWidget extends HookConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    final userStatus = ref.watch(accountStatusProvider(uname));
+    final status = ref.watch(accountStatusProvider(uname));
+    final account = ref.watch(accountProvider(uname));
 
     return Padding(
       padding: padding ?? EdgeInsets.symmetric(horizontal: 27, vertical: 4),
       child: Row(
         spacing: 4,
         children: [
-          if (userStatus.value?.isOnline ?? false)
+          if (status.value?.isOnline ?? false)
             Icon(
               Symbols.circle,
               fill: 1,
@@ -119,13 +122,24 @@ class AccountStatusWidget extends HookConsumerWidget {
               size: 16,
             ).padding(right: 4)
           else
-            Icon(Symbols.circle, color: Colors.grey, size: 16).padding(all: 4),
-          if (userStatus.value?.isCustomized ?? false)
-            Text(userStatus.value?.label ?? 'unknown'.tr())
+            Icon(
+              Symbols.circle,
+              color: Colors.grey,
+              size: 16,
+            ).padding(right: 4),
+          if (status.value?.isCustomized ?? false)
+            Text(status.value?.label ?? 'unknown'.tr())
           else
-            Text((userStatus.value?.label ?? 'offline').toLowerCase()).tr(),
+            Text((status.value?.label ?? 'offline').toLowerCase()).tr(),
+          if (!(status.value?.isOnline ?? false) &&
+              account.value?.profile.lastSeenAt != null)
+            Flexible(
+              child: Text(
+                account.value!.profile.lastSeenAt!.formatRelative(context),
+              ).opacity(0.75),
+            ),
         ],
       ),
-    ).opacity((userStatus.value?.isCustomized ?? false) ? 1 : 0.85);
+    ).opacity((status.value?.isCustomized ?? false) ? 1 : 0.85);
   }
 }