1- <t:base title =" My Access Logs" >
2- <link rel =" stylesheet" href =" ${ pageContext. request. contextPath } /css/access-log.css" >
3- <div class =" container" >
4- <h2 >View My Access Logs</h2 >
5- <% if (error != null ) { % >
6- <div class =" error" >
7- <%= error % >
8- </div >
9- <% } % >
1+ <%@ page language =" java" contentType =" text/html; charset=UTF-8" pageEncoding =" UTF-8" %>
2+ <%@ taglib prefix =" c" uri =" http://java.sun.com/jsp/jstl/core" %>
3+ <%@ taglib prefix =" t" tagdir =" /WEB-INF/tags/layout" %>
104
11- <% if (accessLogList != null ) { % >
12- <div >Number of logs: <%= accessLogList. size() % >
5+ <t:base title =" My Access Logs" description =" View your account access history" >
6+ <div class =" max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8" >
7+ <!-- Header -->
8+ <div class =" mb-8" >
9+ <h1 class =" text-3xl font-bold text-neutral-900" >Access Logs</h1 >
10+ <p class =" mt-2 text-neutral-600" >View your account activity and security history.</p >
1311 </div >
14- <% } % >
1512
16- <form method =" get" action =" <%= request. getContextPath() % > /api/accessLog" >
17- <label for =" startDate" >Start Date:</label >
18- <input type =" date" id =" startDate" name =" startDate" value =" <%= request. getParameter("
19- startDate" ) != null ? request. getParameter(" startDate" ) : " " % >" />
20- <label for =" endDate" >End Date:</label >
21- <input type =" date" id =" endDate" name =" endDate" value =" <%= request. getParameter(" endDate" )
22- != null ? request. getParameter(" endDate" ) : " " % >" />
23- <button type =" submit" >Search</button >
24- <a href =" <%= request. getContextPath() % > /api/accessLog"
25- style =" margin-left :18px ; color :#555 ; text-decoration :underline ;" >Show
26- All</a >
27- </form >
28- <table >
29- <tr >
30- <th >No.</th >
31- <th >Action</th >
32- <th >Timestamp</th >
33- </tr >
34- <% if (accessLogList != null && ! accessLogList. isEmpty()) { int idx= 1 ; for (AccessLog log :
35- accessLogList) { % >
36- <tr >
37- <td >
38- <%= idx++ % >
39- </td >
40- <td >
41- <%= log. getAction() % >
42- </td >
43- <td >
44- <% LocalDateTime ts= log. getTimestamp(); String formattedTs= " " ; try {
45- formattedTs= ts != null ? ts. format(dtf) : " " ; } catch (Exception e) {
46- formattedTs= ts != null ? ts. toString() : " " ; } % >
47- <%= formattedTs % >
48- </td >
49- </tr >
50- <% } } else { % >
51- <tr >
52- <td colspan =" 3" class =" no-data" >No access logs
53- found.</td >
54- </tr >
55- <% } % >
56- </table >
57- </div >
58- </t:base >
13+ <!-- Error Message -->
14+ <c:if test =" ${ not empty error } " >
15+ <div class =" mb-6 bg-red-50 border-l-4 border-red-500 p-4" role =" alert" >
16+ <div class =" flex" >
17+ <div class =" flex-shrink-0" >
18+ <svg class =" h-5 w-5 text-red-400" viewBox =" 0 0 20 20" fill =" currentColor" >
19+ <path fill-rule =" evenodd"
20+ d =" M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
21+ clip-rule =" evenodd" />
22+ </svg >
23+ </div >
24+ <div class =" ml-3" >
25+ <p class =" text-sm text-red-700" >
26+ <c:out value =" ${ error } " />
27+ </p >
28+ </div >
29+ </div >
30+ </div >
31+ </c:if >
32+
33+ <!-- Search/Filter Section -->
34+ <div class =" bg-white shadow rounded-lg mb-8" >
35+ <div class =" px-4 py-5 sm:p-6" >
36+ <form action =" ${ pageContext. request. contextPath } /api/accessLog" method =" get"
37+ class =" grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6 items-end" >
38+ <div class =" sm:col-span-2" >
39+ <label for =" startDate" class =" block text-sm font-medium text-neutral-700" >Start
40+ Date</label >
41+ <div class =" mt-1" >
42+ <input type =" date" name =" startDate" id =" startDate" value =" ${ param. startDate } "
43+ class =" shadow-sm focus:ring-brand-primary focus:border-brand-primary block w-full sm:text-sm border-neutral-300 rounded-md" >
44+ </div >
45+ </div >
46+
47+ <div class =" sm:col-span-2" >
48+ <label for =" endDate" class =" block text-sm font-medium text-neutral-700" >End
49+ Date</label >
50+ <div class =" mt-1" >
51+ <input type =" date" name =" endDate" id =" endDate" value =" ${ param. endDate } "
52+ class =" shadow-sm focus:ring-brand-primary focus:border-brand-primary block w-full sm:text-sm border-neutral-300 rounded-md" >
53+ </div >
54+ </div >
55+
56+ <div class =" sm:col-span-2 flex space-x-3" >
57+ <button type =" submit"
58+ class =" inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-brand-primary hover:bg-brand-secondary focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand-primary" >
59+ Search
60+ </button >
61+ <a href =" ${ pageContext. request. contextPath } /api/accessLog"
62+ class =" inline-flex items-center px-4 py-2 border border-neutral-300 text-sm font-medium rounded-md text-neutral-700 bg-white hover:bg-neutral-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand-primary" >
63+ Reset
64+ </a >
65+ </div >
66+ </form >
67+ </div >
68+ </div >
69+
70+ <!-- Results Table -->
71+ <div class =" bg-white shadow overflow-hidden sm:rounded-lg" >
72+ <div class =" px-4 py-5 sm:px-6 flex justify-between items-center" >
73+ <h3 class =" text-lg leading-6 font-medium text-neutral-900" >Log Entries</h3 >
74+ <c:if test =" ${ not empty accessLogList } " >
75+ <span
76+ class =" inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800" >
77+ ${ accessLogList. size() } records
78+ </span >
79+ </c:if >
80+ </div >
81+
82+ <div class =" border-t border-neutral-200" >
83+ <div class =" overflow-x-auto" >
84+ <table class =" min-w-full divide-y divide-neutral-200" >
85+ <thead class =" bg-neutral-50" >
86+ <tr >
87+ <th scope =" col"
88+ class =" px-6 py-3 text-left text-xs font-medium text-neutral-500 uppercase tracking-wider" >
89+ No.</th >
90+ <th scope =" col"
91+ class =" px-6 py-3 text-left text-xs font-medium text-neutral-500 uppercase tracking-wider" >
92+ Action</th >
93+ <th scope =" col"
94+ class =" px-6 py-3 text-left text-xs font-medium text-neutral-500 uppercase tracking-wider" >
95+ Timestamp</th >
96+ <th scope =" col"
97+ class =" px-6 py-3 text-left text-xs font-medium text-neutral-500 uppercase tracking-wider" >
98+ IP Address</th >
99+ </tr >
100+ </thead >
101+ <tbody class =" bg-white divide-y divide-neutral-200" >
102+ <c:choose >
103+ <c:when test =" ${ not empty accessLogList } " >
104+ <c:forEach var =" log" items =" ${ accessLogList } " varStatus =" status" >
105+ <tr class =" hover:bg-neutral-50 transition-colors duration-150" >
106+ <td
107+ class =" px-6 py-4 whitespace-nowrap text-sm text-neutral-500" >
108+ ${ status. count }
109+ </td >
110+ <td
111+ class =" px-6 py-4 whitespace-nowrap text-sm font-medium text-neutral-900" >
112+ <c:out value =" ${ log. action } " />
113+ </td >
114+ <td
115+ class =" px-6 py-4 whitespace-nowrap text-sm text-neutral-500" >
116+ <c:out value =" ${ log. formattedTimestamp } " />
117+ </td >
118+ <td
119+ class =" px-6 py-4 whitespace-nowrap text-sm text-neutral-500" >
120+ <c:out
121+ value =" ${ log. ipAddress != null ? log. ipAddress : ' -' } " />
122+ </td >
123+ </tr >
124+ </c:forEach >
125+ </c:when >
126+ <c:otherwise >
127+ <tr >
128+ <td colspan =" 4"
129+ class =" px-6 py-12 text-center text-sm text-neutral-500" >
130+ <svg class =" mx-auto h-12 w-12 text-neutral-400" fill =" none"
131+ viewBox =" 0 0 24 24" stroke =" currentColor" >
132+ <path stroke-linecap =" round" stroke-linejoin =" round"
133+ stroke-width =" 2"
134+ d =" M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
135+ </svg >
136+ <p class =" mt-2" >No access logs found matching your criteria.</p >
137+ </td >
138+ </tr >
139+ </c:otherwise >
140+ </c:choose >
141+ </tbody >
142+ </table >
143+ </div >
144+ </div >
145+ </div >
146+ </div >
147+ </t:base >
0 commit comments