Skip to content

feat: add last activity date time#57

Merged
RMCampos merged 9 commits into
mainfrom
feat/add-last-activity
May 18, 2026
Merged

feat: add last activity date time#57
RMCampos merged 9 commits into
mainfrom
feat/add-last-activity

Conversation

@RMCampos
Copy link
Copy Markdown
Owner

This pull request adds support for tracking and displaying the user's last login time throughout the application. It introduces a new lastLogin field to the user entity, updates the database schema, ensures the backend populates this field on login, and exposes it via API responses. The frontend is updated to display the last login time in the sidebar footer. Below are the key changes:

Backend: User Entity, API, and Database

  • Added a lastLogin field to the UserEntity class, including getter and setter methods, and updated the database schema to persist this value (last_login column). [1] [2] [3]
  • Updated the authentication service to set the lastLogin field to the current time on successful user sign-in.
  • Modified UserResponse and UserResponseWithToken records to include the lastLogin field, and updated their factory methods to populate this value. The UserResponseWithToken uses a formatted string for display. (Ff158ef4L11R12, [1] [2] [3]
  • Updated related tests to account for the new lastLogin field in user response objects. [1] [2] [3] [4] [5] [6] [7] [8]

Frontend: Types, Context, and UI

  • Added lastLogin to the user-related TypeScript types (UserResponse, SignInResponse) and updated the authentication context to store and provide this value. [1] [2] [3]
  • Updated the Sidebar component to display the user's last login time in the footer area.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds tracking of a user's last sign-in timestamp. The backend records lastLogin on the UserEntity (new column via Flyway migration), updates LoginRequest to also carry a client timezone, formats the timestamp into a string in UserResponse/UserResponseWithToken via a new TimeAgoUtil.formatLastSeen, and the frontend stores the value in auth context and renders "Last seen …" in the sidebar footer.

Changes:

  • New lastLogin column/field + Flyway migration; populated on successful sign-in.
  • LoginRequest gains a timezone field (annotated @NotBlank) used to format lastLogin server-side.
  • Frontend types, AuthProvider, and Sidebar updated to send browser timezone and display the last-seen timestamp.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
server/src/main/resources/db/migration/V202605171000__add_user_last_login.sql Adds last_login column to users table.
server/src/main/java/br/com/tasknoteapp/server/entity/UserEntity.java New lastLogin field + accessors.
server/src/main/java/br/com/tasknoteapp/server/request/LoginRequest.java Adds required timezone field (@NotBlank) and updates constructor.
server/src/main/java/br/com/tasknoteapp/server/util/TimeAgoUtil.java Adds formatLastSeen using ZoneId; defaults to America/Sao_Paulo.
server/src/main/java/br/com/tasknoteapp/server/response/UserResponse.java Adds lastLogin (String) and timezone parameter to factory.
server/src/main/java/br/com/tasknoteapp/server/response/UserResponseWithToken.java Same as above plus token.
server/src/main/java/br/com/tasknoteapp/server/service/AuthService.java Sets lastLogin on sign-in; threads timezone through response factories (null in several paths).
server/src/test/.../AuthServiceTest.java, AuthenticationControllerTest.java, UserControllerTest.java, UserSessionControllerTest.java, UserSessionServiceTest.java Updated to match new constructor signatures and JSON payloads.
client/src/types/UserResponse.ts, SigninResponse.ts Add lastLogin field.
client/src/context/AuthProvider.tsx Sends browser timezone on sign-in; stores lastLogin on the user.
client/src/components/Sidebar/index.tsx Renders "Last seen {user.lastLogin}" in the footer.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/src/main/java/br/com/tasknoteapp/server/request/LoginRequest.java Outdated
Comment thread server/src/main/java/br/com/tasknoteapp/server/util/TimeAgoUtil.java Outdated
Comment thread server/src/main/java/br/com/tasknoteapp/server/response/UserResponse.java Outdated
Comment thread client/src/components/Sidebar/index.tsx Outdated
Comment thread server/src/main/java/br/com/tasknoteapp/server/service/AuthService.java Outdated
Comment thread server/src/main/java/br/com/tasknoteapp/server/util/TimeAgoUtil.java Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Comment on lines +52 to +61
const utcString = user.lastLogin.endsWith('Z') ? user.lastLogin : `${user.lastLogin}Z`;
const fmtted = new Date(utcString).toLocaleString(navigator.language, {
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
setLastSeen(fmtted);
Comment thread client/src/components/Sidebar/index.tsx Outdated
</small>
{lastSeen && (
<div>
<small>{`Last seen ${lastSeen}`}</small>
Comment on lines +561 to +578
private UserEntity cloneUser(UserEntity user, LocalDateTime lastLogin) {
UserEntity u = new UserEntity();
u.setId(user.getId());
u.setEmail(user.getEmail());
u.setPassword(user.getPassword());
u.setAdmin(user.getAdmin());
u.setCreatedAt(user.getCreatedAt());
u.setInactivatedAt(user.getInactivatedAt());
u.setName(user.getName());
u.setEmailConfirmedAt(user.getEmailConfirmedAt());
u.setEmailUuid(user.getEmailUuid());
u.setResetPasswordExpiration(user.getResetPasswordExpiration());
u.setResetToken(user.getResetToken());
u.setLang(user.getLang());
u.setLastPasswordChange(user.getLastPasswordChange());
u.setLastLogin(lastLogin);
return u;
}
@RMCampos
Copy link
Copy Markdown
Owner Author

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented May 18, 2026

@copilot apply changes based on the comments in this thread

Implemented the requested thread updates in commit 39a3352: removed the fragile cloneUser copy flow (now we keep previousLastLogin directly), set persisted sign-in timestamps in UTC, localized the Sidebar last-seen text via t('sidebar_last_seen', { time }), and added invalid-date guarding before rendering.

Screenshot: /tmp/sidebar-last-seen.png

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • accounts.google.com
    • Triggering command: /proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --no-sandbox --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5171 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-HARVEc --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12498529954500859893,12024697574664425738,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version --pseudonymization-salt-handle=7,i,16724051204453066541,3076772543419498041,4 (dns block)
    • Triggering command: /opt/google/chrome/chrome /usr/bin/google-chrome-stable --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation (dns block)
  • cdn.jsdelivr.net
    • Triggering command: /proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --no-sandbox --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5171 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-HARVEc --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12498529954500859893,12024697574664425738,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version --pseudonymization-salt-handle=7,i,16724051204453066541,3076772543419498041,4 (dns block)
    • Triggering command: /opt/google/chrome/chrome /usr/bin/google-chrome-stable --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation (dns block)
  • checkstyle.org
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-8020627fcb755699/dbs/java/working/files-to-index10482569793145943661.list --sourceArchiveDir=/tmp/codeql-scratch-8020627fcb755699/dbs/java/src --outputDir=/tmp/codeql-scratch-8020627fcb755699/dbs/java/trap/java r ndor/bin/git (dns block)
  • clients2.google.com
    • Triggering command: /proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --no-sandbox --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5171 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-HARVEc --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12498529954500859893,12024697574664425738,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version --pseudonymization-salt-handle=7,i,16724051204453066541,3076772543419498041,4 (dns block)
    • Triggering command: /opt/google/chrome/chrome /usr/bin/google-chrome-stable --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation (dns block)
  • download.cypress.io
    • Triggering command: /usr/local/bin/node node dist/index.js --exec install (dns block)
  • fonts.googleapis.com
    • Triggering command: /proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --no-sandbox --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5171 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-HARVEc --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12498529954500859893,12024697574664425738,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version --pseudonymization-salt-handle=7,i,16724051204453066541,3076772543419498041,4 (dns block)
    • Triggering command: /opt/google/chrome/chrome /usr/bin/google-chrome-stable --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation (dns block)
  • fonts.gstatic.com
    • Triggering command: /proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --no-sandbox --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5171 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-HARVEc --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12498529954500859893,12024697574664425738,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version --pseudonymization-salt-handle=7,i,16724051204453066541,3076772543419498041,4 (dns block)
    • Triggering command: /opt/google/chrome/chrome /usr/bin/google-chrome-stable --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation (dns block)
  • safebrowsingohttpgateway.googleapis.com
    • Triggering command: /proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --no-sandbox --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5171 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-HARVEc --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12498529954500859893,12024697574664425738,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version --pseudonymization-salt-handle=7,i,16724051204453066541,3076772543419498041,4 (dns block)
    • Triggering command: /opt/google/chrome/chrome /usr/bin/google-chrome-stable --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation (dns block)
  • www.google.com
    • Triggering command: /proc/self/exe /proc/self/exe --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --no-sandbox --disable-dev-shm-usage --use-angle=swiftshader-webgl --mute-audio --crashpad-handler-pid=5171 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/puppeteer_dev_chrome_profile-HARVEc --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,12498529954500859893,12024697574664425738,262144 --enable-features=PdfOopif --disable-features=AcceptCHFrame,IsolateSandboxedIframes,MediaRouter,OptimizationHints,PaintHolding,ProcessPerSiteUpToMainFrameThreshold,RenderDocument,Translate --variations-seed-version --pseudonymization-salt-handle=7,i,16724051204453066541,3076772543419498041,4 (dns block)
    • Triggering command: /opt/google/chrome/chrome /usr/bin/google-chrome-stable --allow-pre-commit-input --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-crash-reporter --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-infobars --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-REDACTEDing --disable-search-engine-choice-screen --disable-sync --enable-automation (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@RMCampos RMCampos merged commit a6bdd10 into main May 18, 2026
5 of 6 checks passed
@RMCampos RMCampos deleted the feat/add-last-activity branch May 18, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants