@salesforce/webapp-template-app-react-sample-b2e-experimental 1.64.0 → 1.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/CHANGELOG.md +16 -0
  2. package/dist/force-app/main/default/data/Agent__c.json +79 -0
  3. package/dist/force-app/main/default/data/Application__c.json +10 -10
  4. package/dist/force-app/main/default/data/Contact.json +44 -0
  5. package/dist/force-app/main/default/data/Maintenance_Request__c.json +30 -30
  6. package/dist/force-app/main/default/data/Property__c.json +25 -25
  7. package/dist/force-app/main/default/data/data-plan.json +13 -1
  8. package/dist/force-app/main/default/objects/Agent__c/Agent__c.object-meta.xml +66 -0
  9. package/dist/force-app/main/default/objects/Agent__c/fields/Agent_Type__c.field-meta.xml +37 -0
  10. package/dist/force-app/main/default/objects/Agent__c/fields/Availability__c.field-meta.xml +37 -0
  11. package/dist/force-app/main/default/objects/Agent__c/fields/Emergency_Alt__c.field-meta.xml +11 -0
  12. package/dist/force-app/main/default/objects/Agent__c/fields/Language__c.field-meta.xml +42 -0
  13. package/dist/force-app/main/default/objects/Agent__c/fields/License_Expiry__c.field-meta.xml +11 -0
  14. package/dist/force-app/main/default/objects/Agent__c/fields/License_Number__c.field-meta.xml +14 -0
  15. package/dist/force-app/main/default/objects/Agent__c/fields/Office_Location__c.field-meta.xml +42 -0
  16. package/dist/force-app/main/default/objects/Agent__c/fields/Territory__c.field-meta.xml +42 -0
  17. package/dist/force-app/main/default/objects/Maintenance_Request__c/fields/User__c.field-meta.xml +1 -1
  18. package/dist/force-app/main/default/objects/Property__c/fields/Agent__c.field-meta.xml +1 -1
  19. package/dist/force-app/main/default/permissionsets/Property_Management_Access.permissionset-meta.xml +53 -25
  20. package/dist/force-app/main/default/webapplications/appreactsampleb2e/package-lock.json +18307 -0
  21. package/dist/force-app/main/default/webapplications/appreactsampleb2e/package.json +9 -7
  22. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/applications.ts +142 -0
  23. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/dashboard.ts +1 -2
  24. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/maintenance.ts +63 -6
  25. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/properties.ts +1 -2
  26. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/appLayout.tsx +4 -0
  27. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/AgentforceConversationClient.tsx +127 -0
  28. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ApplicationDetailsModal.tsx +150 -0
  29. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ApplicationsTable.tsx +105 -0
  30. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/MaintenanceDetailsModal.tsx +191 -0
  31. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/PropertyDetailsModal.tsx +274 -0
  32. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/StatusBadge.tsx +17 -17
  33. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/TopBar.tsx +37 -7
  34. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/VerticalNav.tsx +1 -5
  35. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/index.ts +6 -0
  36. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/lib/types.ts +6 -2
  37. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Applications.tsx +129 -0
  38. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Home.tsx +28 -13
  39. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Maintenance.tsx +95 -62
  40. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Properties.tsx +22 -2
  41. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/TestAccPage.tsx +19 -0
  42. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/routes.tsx +12 -0
  43. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/types/conversation.ts +21 -0
  44. package/dist/package.json +1 -1
  45. package/package.json +2 -4
  46. package/dist/force-app/main/default/applications/Property_Management.app-meta.xml +0 -26
  47. package/dist/force-app/main/default/tabs/Application__c.tab-meta.xml +0 -6
  48. package/dist/force-app/main/default/tabs/Maintenance_Request__c.tab-meta.xml +0 -7
  49. package/dist/force-app/main/default/tabs/Maintenance_Worker__c.tab-meta.xml +0 -6
  50. package/dist/force-app/main/default/tabs/Notification__c.tab-meta.xml +0 -6
  51. package/dist/force-app/main/default/tabs/Property__c.tab-meta.xml +0 -7
  52. package/dist/force-app/main/default/tabs/Tenant__c.tab-meta.xml +0 -7
  53. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/utils.ts +0 -4
@@ -4,8 +4,6 @@ import dashboardIcon from "../assets/icons/dashboard.svg";
4
4
  import filesIcon from "../assets/icons/files.svg";
5
5
  import propertiesIcon from "../assets/icons/properties.svg";
6
6
  import maintenanceIcon from "../assets/icons/maintenance.svg";
7
- import usersIcon from "../assets/icons/users.svg";
8
- import supportIcon from "../assets/icons/support.svg";
9
7
 
10
8
  interface NavItem {
11
9
  path: string;
@@ -15,11 +13,9 @@ interface NavItem {
15
13
 
16
14
  const navItems: NavItem[] = [
17
15
  { path: "/", icon: dashboardIcon, label: "Dashboard" },
18
- { path: "/files", icon: filesIcon, label: "Files" },
16
+ { path: "/applications", icon: filesIcon, label: "Applications" },
19
17
  { path: "/properties", icon: propertiesIcon, label: "Properties" },
20
18
  { path: "/maintenance", icon: maintenanceIcon, label: "Maintenance" },
21
- { path: "/users", icon: usersIcon, label: "Users" },
22
- { path: "/support", icon: supportIcon, label: "Support" },
23
19
  ];
24
20
 
25
21
  export const VerticalNav: React.FC = () => {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * feature-react-agentforce-conversation-client – ACC Conversation Client
3
+ */
4
+
5
+ export { AgentforceConversationClient } from "./components/AgentforceConversationClient";
6
+ export type { AgentforceConversationClientProps, ResolvedEmbedOptions } from "./types/conversation";
@@ -12,7 +12,11 @@ export interface Application {
12
12
  applicantName: string;
13
13
  propertyAddress: string;
14
14
  submittedDate: string;
15
- status: "pending" | "approved" | "rejected";
15
+ status: string;
16
+ employment?: string;
17
+ references?: string;
18
+ startDate?: string;
19
+ propertyName?: string;
16
20
  }
17
21
 
18
22
  export interface MaintenanceRequest {
@@ -20,7 +24,7 @@ export interface MaintenanceRequest {
20
24
  propertyAddress: string;
21
25
  issueType: string;
22
26
  priority: "emergency" | "high" | "medium" | "low";
23
- status: "new" | "assigned" | "scheduled" | "in_progress" | "completed";
27
+ status: string;
24
28
  assignedWorker?: string;
25
29
  scheduledDateTime?: string;
26
30
  description: string;
@@ -0,0 +1,129 @@
1
+ import { useEffect, useState } from "react";
2
+ import { ApplicationsTable } from "../components/ApplicationsTable.js";
3
+ import { ApplicationDetailsModal } from "../components/ApplicationDetailsModal.js";
4
+ import { getApplications, updateApplicationStatus } from "../api/applications.js";
5
+ import type { Application } from "../lib/types.js";
6
+
7
+ export default function Applications() {
8
+ const [applications, setApplications] = useState<Application[]>([]);
9
+ const [loading, setLoading] = useState(true);
10
+ const [selectedApplication, setSelectedApplication] = useState<Application | null>(null);
11
+ const [notification, setNotification] = useState<{
12
+ message: string;
13
+ type: "success" | "error";
14
+ } | null>(null);
15
+
16
+ useEffect(() => {
17
+ loadApplications();
18
+ }, []);
19
+
20
+ // Clear notification after 5 seconds
21
+ useEffect(() => {
22
+ if (notification) {
23
+ const timer = setTimeout(() => {
24
+ setNotification(null);
25
+ }, 5000);
26
+ return () => clearTimeout(timer);
27
+ }
28
+ }, [notification]);
29
+
30
+ const loadApplications = async () => {
31
+ try {
32
+ setLoading(true);
33
+ const data = await getApplications();
34
+ setApplications(data);
35
+ } catch (error) {
36
+ console.error("Error loading applications:", error);
37
+ showNotification("Failed to load applications", "error");
38
+ } finally {
39
+ setLoading(false);
40
+ }
41
+ };
42
+
43
+ const handleRowClick = (application: Application) => {
44
+ setSelectedApplication(application);
45
+ };
46
+
47
+ const handleCloseModal = () => {
48
+ setSelectedApplication(null);
49
+ };
50
+
51
+ const handleSaveStatus = async (applicationId: string, status: string) => {
52
+ try {
53
+ const success = await updateApplicationStatus(applicationId, status);
54
+
55
+ if (success) {
56
+ // Update the local state
57
+ setApplications((prev) =>
58
+ prev.map((app) => (app.id === applicationId ? { ...app, status } : app)),
59
+ );
60
+
61
+ // Update selected application if it's the one being edited
62
+ if (selectedApplication?.id === applicationId) {
63
+ setSelectedApplication({ ...selectedApplication, status });
64
+ }
65
+
66
+ showNotification("Application status updated successfully!", "success");
67
+ } else {
68
+ showNotification("Failed to update application status", "error");
69
+ }
70
+ } catch (error) {
71
+ console.error("Error updating application:", error);
72
+ showNotification("An error occurred while updating the status", "error");
73
+ }
74
+ };
75
+
76
+ const showNotification = (message: string, type: "success" | "error") => {
77
+ setNotification({ message, type });
78
+ };
79
+
80
+ if (loading) {
81
+ return (
82
+ <div className="flex items-center justify-center h-screen bg-gray-50">
83
+ <div className="text-lg text-gray-600">Loading applications...</div>
84
+ </div>
85
+ );
86
+ }
87
+
88
+ return (
89
+ <div className="min-h-screen bg-gray-50">
90
+ {/* Notification */}
91
+ {notification && (
92
+ <div className="fixed top-4 right-4 z-50 animate-slide-in">
93
+ <div
94
+ className={`px-6 py-4 rounded-lg shadow-lg ${
95
+ notification.type === "success" ? "bg-green-500 text-white" : "bg-red-500 text-white"
96
+ }`}
97
+ >
98
+ <div className="flex items-center gap-3">
99
+ <span className="text-lg">{notification.type === "success" ? "✓" : "✕"}</span>
100
+ <p className="font-medium">{notification.message}</p>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ )}
105
+
106
+ {/* Main Content */}
107
+ <div className="max-w-7xl mx-auto p-8">
108
+ {/* Header */}
109
+ <div className="mb-6">
110
+ <h1 className="text-2xl font-bold text-gray-900">Applications</h1>
111
+ <p className="text-gray-600 mt-1">Manage and review rental applications</p>
112
+ </div>
113
+
114
+ {/* Applications Table */}
115
+ <ApplicationsTable applications={applications} onRowClick={handleRowClick} />
116
+ </div>
117
+
118
+ {/* Application Details Modal */}
119
+ {selectedApplication && (
120
+ <ApplicationDetailsModal
121
+ application={selectedApplication}
122
+ isOpen={!!selectedApplication}
123
+ onClose={handleCloseModal}
124
+ onSave={handleSaveStatus}
125
+ />
126
+ )}
127
+ </div>
128
+ );
129
+ }
@@ -69,14 +69,29 @@ export default function Home() {
69
69
  ];
70
70
  };
71
71
 
72
- // Calculate previous month's data (mock for now)
73
- const getPreviousMetrics = () => ({
74
- totalProperties: 12,
75
- unitsAvailable: 78,
76
- occupiedUnits: 422,
77
- });
72
+ // Calculate trends based on current metrics (assuming 10% growth for properties and occupied, 10% decrease for available)
73
+ const calculateTrends = () => {
74
+ const totalPropertiesTrend = Math.round(metrics.totalProperties * 0.1);
75
+ const unitsAvailableTrend = Math.round(metrics.unitsAvailable * 0.1);
76
+ const occupiedUnitsTrend = Math.round(metrics.occupiedUnits * 0.1);
77
+
78
+ return {
79
+ totalProperties: {
80
+ trend: totalPropertiesTrend,
81
+ previous: metrics.totalProperties - totalPropertiesTrend,
82
+ },
83
+ unitsAvailable: {
84
+ trend: unitsAvailableTrend,
85
+ previous: metrics.unitsAvailable + unitsAvailableTrend,
86
+ },
87
+ occupiedUnits: {
88
+ trend: occupiedUnitsTrend,
89
+ previous: metrics.occupiedUnits - occupiedUnitsTrend,
90
+ },
91
+ };
92
+ };
78
93
 
79
- const previousMetrics = getPreviousMetrics();
94
+ const trends = calculateTrends();
80
95
 
81
96
  if (loading) {
82
97
  return (
@@ -125,28 +140,28 @@ export default function Home() {
125
140
  title="Total Properties"
126
141
  value={metrics.totalProperties}
127
142
  trend={{
128
- value: 20,
143
+ value: trends.totalProperties.trend,
129
144
  isPositive: true,
130
145
  }}
131
- subtitle={`Last month total ${previousMetrics.totalProperties}`}
146
+ subtitle={`Last month total ${trends.totalProperties.previous}`}
132
147
  />
133
148
  <StatCard
134
149
  title="Units Available"
135
150
  value={metrics.unitsAvailable}
136
151
  trend={{
137
- value: 10,
152
+ value: trends.unitsAvailable.trend,
138
153
  isPositive: false,
139
154
  }}
140
- subtitle={`Last month total ${previousMetrics.unitsAvailable}/${metrics.totalProperties}`}
155
+ subtitle={`Last month total ${trends.unitsAvailable.previous}/${metrics.totalProperties}`}
141
156
  />
142
157
  <StatCard
143
158
  title="Occupied Units"
144
159
  value={metrics.occupiedUnits}
145
160
  trend={{
146
- value: 5,
161
+ value: trends.occupiedUnits.trend,
147
162
  isPositive: true,
148
163
  }}
149
- subtitle={`Last month total ${previousMetrics.occupiedUnits}`}
164
+ subtitle={`Last month total ${trends.occupiedUnits.previous}`}
150
165
  />
151
166
  </div>
152
167
 
@@ -1,19 +1,34 @@
1
1
  import { useEffect, useState } from "react";
2
2
  import { ChevronDown } from "lucide-react";
3
- import { getAllMaintenanceRequests } from "../api/maintenance.js";
3
+ import { getAllMaintenanceRequests, updateMaintenanceStatus } from "../api/maintenance.js";
4
4
  import type { MaintenanceRequest } from "../lib/types.js";
5
5
  import { UserAvatar } from "../components/UserAvatar.js";
6
- import { PriorityBadge } from "../components/PriorityBadge.js";
7
6
  import { StatusBadge } from "../components/StatusBadge.js";
7
+ import { MaintenanceDetailsModal } from "../components/MaintenanceDetailsModal.js";
8
8
 
9
9
  export default function Maintenance() {
10
10
  const [requests, setRequests] = useState<MaintenanceRequest[]>([]);
11
11
  const [loading, setLoading] = useState(true);
12
+ const [selectedRequest, setSelectedRequest] = useState<MaintenanceRequest | null>(null);
13
+ const [notification, setNotification] = useState<{
14
+ message: string;
15
+ type: "success" | "error";
16
+ } | null>(null);
12
17
 
13
18
  useEffect(() => {
14
19
  loadMaintenanceRequests();
15
20
  }, []);
16
21
 
22
+ // Clear notification after 5 seconds
23
+ useEffect(() => {
24
+ if (notification) {
25
+ const timer = setTimeout(() => {
26
+ setNotification(null);
27
+ }, 5000);
28
+ return () => clearTimeout(timer);
29
+ }
30
+ }, [notification]);
31
+
17
32
  const loadMaintenanceRequests = async () => {
18
33
  try {
19
34
  setLoading(true);
@@ -26,6 +41,41 @@ export default function Maintenance() {
26
41
  }
27
42
  };
28
43
 
44
+ const handleRowClick = (request: MaintenanceRequest) => {
45
+ setSelectedRequest(request);
46
+ };
47
+
48
+ const handleCloseModal = () => {
49
+ setSelectedRequest(null);
50
+ };
51
+
52
+ const handleSaveStatus = async (requestId: string, status: string) => {
53
+ try {
54
+ const success = await updateMaintenanceStatus(requestId, status);
55
+
56
+ if (success) {
57
+ // Update the local state
58
+ setRequests((prev) => prev.map((req) => (req.id === requestId ? { ...req, status } : req)));
59
+
60
+ // Update selected request if it's the one being edited
61
+ if (selectedRequest?.id === requestId) {
62
+ setSelectedRequest({ ...selectedRequest, status });
63
+ }
64
+
65
+ showNotification("Maintenance request status updated successfully!", "success");
66
+ } else {
67
+ showNotification("Failed to update maintenance request status", "error");
68
+ }
69
+ } catch (error) {
70
+ console.error("Error updating maintenance request:", error);
71
+ showNotification("An error occurred while updating the status", "error");
72
+ }
73
+ };
74
+
75
+ const showNotification = (message: string, type: "success" | "error") => {
76
+ setNotification({ message, type });
77
+ };
78
+
29
79
  if (loading) {
30
80
  return (
31
81
  <div className="flex items-center justify-center h-screen bg-gray-50">
@@ -37,30 +87,44 @@ export default function Maintenance() {
37
87
  return (
38
88
  <div className="min-h-screen bg-gray-50 p-8">
39
89
  <div className="max-w-7xl mx-auto">
90
+ {/* Notification */}
91
+ {notification && (
92
+ <div className="fixed top-4 right-4 z-50 animate-slide-in">
93
+ <div
94
+ className={`px-6 py-4 rounded-lg shadow-lg ${
95
+ notification.type === "success"
96
+ ? "bg-green-500 text-white"
97
+ : "bg-red-500 text-white"
98
+ }`}
99
+ >
100
+ <div className="flex items-center gap-3">
101
+ <span className="text-lg">{notification.type === "success" ? "✓" : "✕"}</span>
102
+ <p className="font-medium">{notification.message}</p>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ )}
107
+
108
+ {/* Header */}
109
+ <div className="mb-6">
110
+ <h1 className="text-2xl font-bold text-gray-900">Maintenance</h1>
111
+ <p className="text-gray-600 mt-1">Track and manage maintenance requests</p>
112
+ </div>
113
+
40
114
  {/* Table Header */}
41
115
  <div className="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
42
116
  <div className="grid grid-cols-12 gap-4 px-6 py-4 bg-gray-50 border-b border-gray-200">
43
- <div className="col-span-4 flex items-center gap-2">
117
+ <div className="col-span-6 flex items-center gap-2">
44
118
  <span className="text-sm font-semibold text-purple-700 uppercase tracking-wide">
45
119
  Maintenance Task
46
120
  </span>
47
121
  <ChevronDown className="w-4 h-4 text-purple-700" />
48
122
  </div>
49
- <div className="col-span-2">
123
+ <div className="col-span-4">
50
124
  <span className="text-sm font-semibold text-purple-700 uppercase tracking-wide">
51
125
  Tenant Unit
52
126
  </span>
53
127
  </div>
54
- <div className="col-span-2">
55
- <span className="text-sm font-semibold text-purple-700 uppercase tracking-wide">
56
- Assigned to
57
- </span>
58
- </div>
59
- <div className="col-span-2">
60
- <span className="text-sm font-semibold text-purple-700 uppercase tracking-wide">
61
- Date
62
- </span>
63
- </div>
64
128
  <div className="col-span-2">
65
129
  <span className="text-sm font-semibold text-purple-700 uppercase tracking-wide">
66
130
  Status
@@ -76,10 +140,11 @@ export default function Maintenance() {
76
140
  requests.map((request) => (
77
141
  <div
78
142
  key={request.id}
79
- className="grid grid-cols-12 gap-4 px-6 py-5 hover:bg-gray-50 transition-colors"
143
+ onClick={() => handleRowClick(request)}
144
+ className="grid grid-cols-12 gap-4 px-6 py-5 hover:bg-gray-50 transition-colors cursor-pointer"
80
145
  >
81
146
  {/* Maintenance Task */}
82
- <div className="col-span-4 flex items-center gap-4">
147
+ <div className="col-span-6 flex items-center gap-4">
83
148
  {/* Task Image */}
84
149
  <div className="w-16 h-16 rounded-lg bg-gray-200 flex-shrink-0 overflow-hidden">
85
150
  {request.imageUrl ? (
@@ -97,18 +162,15 @@ export default function Maintenance() {
97
162
 
98
163
  {/* Task Details */}
99
164
  <div className="flex-1 min-w-0">
100
- <div className="flex items-center gap-2 mb-1">
101
- <h3 className="font-semibold text-gray-900 truncate">
102
- {request.description}
103
- </h3>
104
- {request.priority && <PriorityBadge priority={request.priority} />}
105
- </div>
165
+ <h3 className="font-semibold text-gray-900 truncate mb-1">
166
+ {request.description}
167
+ </h3>
106
168
  <p className="text-sm text-gray-500">By Tenant</p>
107
169
  </div>
108
170
  </div>
109
171
 
110
172
  {/* Tenant Unit */}
111
- <div className="col-span-2 flex items-center">
173
+ <div className="col-span-4 flex items-center">
112
174
  <div className="flex items-center gap-3">
113
175
  <UserAvatar name={request.tenantName || "Unknown"} size="md" />
114
176
  <div className="min-w-0">
@@ -122,45 +184,6 @@ export default function Maintenance() {
122
184
  </div>
123
185
  </div>
124
186
 
125
- {/* Assigned to */}
126
- <div className="col-span-2 flex items-center">
127
- {request.assignedWorkerName ? (
128
- <div className="flex items-center gap-3">
129
- <UserAvatar name={request.assignedWorkerName} size="md" />
130
- <div className="min-w-0">
131
- <p className="text-sm font-medium text-gray-900 truncate">
132
- {request.assignedWorkerName}
133
- </p>
134
- <p className="text-sm text-gray-500 truncate">
135
- {request.assignedWorkerOrg}
136
- </p>
137
- </div>
138
- </div>
139
- ) : (
140
- <span className="text-sm text-gray-400">Unassigned</span>
141
- )}
142
- </div>
143
-
144
- {/* Date */}
145
- <div className="col-span-2 flex items-center">
146
- <div className="flex items-center gap-2 text-sm text-gray-700">
147
- <svg
148
- className="w-4 h-4"
149
- fill="none"
150
- stroke="currentColor"
151
- viewBox="0 0 24 24"
152
- >
153
- <path
154
- strokeLinecap="round"
155
- strokeLinejoin="round"
156
- strokeWidth={2}
157
- d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
158
- />
159
- </svg>
160
- <span>{request.formattedDate || "Not scheduled"}</span>
161
- </div>
162
- </div>
163
-
164
187
  {/* Status */}
165
188
  <div className="col-span-2 flex items-center">
166
189
  <StatusBadge status={request.status} />
@@ -170,6 +193,16 @@ export default function Maintenance() {
170
193
  )}
171
194
  </div>
172
195
  </div>
196
+
197
+ {/* Maintenance Details Modal */}
198
+ {selectedRequest && (
199
+ <MaintenanceDetailsModal
200
+ request={selectedRequest}
201
+ isOpen={!!selectedRequest}
202
+ onClose={handleCloseModal}
203
+ onSave={handleSaveStatus}
204
+ />
205
+ )}
173
206
  </div>
174
207
  </div>
175
208
  );
@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
2
2
  import { getProperties } from "../api/properties.js";
3
3
  import type { Property } from "../lib/types.js";
4
4
  import { PropertyCard } from "../components/PropertyCard.js";
5
+ import { PropertyDetailsModal } from "../components/PropertyDetailsModal.js";
5
6
  import { Button } from "@/components/ui/button";
6
7
 
7
8
  export default function Properties() {
@@ -10,6 +11,7 @@ export default function Properties() {
10
11
  const [loadingMore, setLoadingMore] = useState(false);
11
12
  const [hasNextPage, setHasNextPage] = useState(false);
12
13
  const [endCursor, setEndCursor] = useState<string | null>(null);
14
+ const [selectedProperty, setSelectedProperty] = useState<Property | null>(null);
13
15
 
14
16
  useEffect(() => {
15
17
  loadProperties();
@@ -46,8 +48,11 @@ export default function Properties() {
46
48
  };
47
49
 
48
50
  const handlePropertyClick = (property: Property) => {
49
- console.log("Property clicked:", property);
50
- // TODO: Navigate to property details page
51
+ setSelectedProperty(property);
52
+ };
53
+
54
+ const handleCloseModal = () => {
55
+ setSelectedProperty(null);
51
56
  };
52
57
 
53
58
  if (loading) {
@@ -61,6 +66,12 @@ export default function Properties() {
61
66
  return (
62
67
  <div className="min-h-screen bg-gray-50 p-8">
63
68
  <div className="max-w-7xl mx-auto">
69
+ {/* Header */}
70
+ <div className="mb-6">
71
+ <h1 className="text-2xl font-bold text-gray-900">Properties</h1>
72
+ <p className="text-gray-600 mt-1">Browse and manage available properties</p>
73
+ </div>
74
+
64
75
  {/* Properties Grid */}
65
76
  {properties.length === 0 ? (
66
77
  <div className="text-center py-12">
@@ -88,6 +99,15 @@ export default function Properties() {
88
99
  )}
89
100
  </>
90
101
  )}
102
+
103
+ {/* Property Details Modal */}
104
+ {selectedProperty && (
105
+ <PropertyDetailsModal
106
+ property={selectedProperty}
107
+ isOpen={!!selectedProperty}
108
+ onClose={handleCloseModal}
109
+ />
110
+ )}
91
111
  </div>
92
112
  </div>
93
113
  );
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+
7
+ import AgentforceConversationClient from "../components/AgentforceConversationClient";
8
+
9
+ export default function TestAccPage() {
10
+ return (
11
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
12
+ <div className="text-center">
13
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">ACC</h1>
14
+ <p className="text-lg text-gray-600 mb-8">Welcome to your ACC application.</p>
15
+ </div>
16
+ <AgentforceConversationClient />
17
+ </div>
18
+ );
19
+ }
@@ -2,8 +2,10 @@ import type { RouteObject } from 'react-router';
2
2
  import AppLayout from './appLayout';
3
3
  import Home from './pages/Home';
4
4
  import NotFound from './pages/NotFound';
5
+ import TestAccPage from "./pages/TestAccPage";
5
6
  import Maintenance from "./pages/Maintenance";
6
7
  import Properties from "./pages/Properties";
8
+ import Applications from "./pages/Applications";
7
9
 
8
10
  export const routes: RouteObject[] = [
9
11
  {
@@ -19,6 +21,11 @@ export const routes: RouteObject[] = [
19
21
  path: '*',
20
22
  element: <NotFound />
21
23
  },
24
+ {
25
+ path: "test-acc",
26
+ element: <TestAccPage />,
27
+ handle: { showInNavigation: true, label: "Test ACC" }
28
+ },
22
29
  {
23
30
  path: "maintenance",
24
31
  element: <Maintenance />,
@@ -28,6 +35,11 @@ export const routes: RouteObject[] = [
28
35
  path: "properties",
29
36
  element: <Properties />,
30
37
  handle: { showInNavigation: true, label: "Properties" }
38
+ },
39
+ {
40
+ path: "applications",
41
+ element: <Applications />,
42
+ handle: { showInNavigation: true, label: "Applications" }
31
43
  }
32
44
  ]
33
45
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+
7
+ import type { AgentforceClientConfig } from "@salesforce/agentforce-conversation-client";
8
+
9
+ export interface ResolvedEmbedOptions {
10
+ salesforceOrigin?: string;
11
+ frontdoorUrl?: string;
12
+ }
13
+
14
+ export interface AgentforceConversationClientProps {
15
+ /** Optional config from consumer. Passed through to the embed client as-is. */
16
+ agentforceClientConfig?: AgentforceClientConfig;
17
+ /** Optional. If not provided, resolved internally (e.g. from /__lo/frontdoor in dev, window.location.origin in prod). */
18
+ salesforceOrigin?: string;
19
+ /** Optional. If not provided, resolved internally in dev via /__lo/frontdoor. */
20
+ frontdoorUrl?: string;
21
+ }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-base-sfdx-project-experimental",
3
- "version": "1.64.0",
3
+ "version": "1.66.0",
4
4
  "description": "Base SFDX project template",
5
5
  "private": true,
6
6
  "files": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/webapp-template-app-react-sample-b2e-experimental",
3
- "version": "1.64.0",
3
+ "version": "1.66.0",
4
4
  "description": "B2E starter app template",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "author": "",
@@ -31,9 +31,7 @@
31
31
  "targets": {
32
32
  "build": {
33
33
  "executor": "@salesforce/webapp-template-cli-experimental:apply-patches",
34
- "options": {
35
- "skipDependencyChanges": true
36
- }
34
+ "dependsOn": []
37
35
  },
38
36
  "watch": {
39
37
  "executor": "@salesforce/webapp-template-cli-experimental:watch-patches"
@@ -1,26 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8" ?>
2
- <CustomApplication xmlns="http://soap.sforce.com/2006/04/metadata">
3
- <brand>
4
- <headerColor>#0176D3</headerColor>
5
- <shouldOverrideOrgTheme>false</shouldOverrideOrgTheme>
6
- </brand>
7
- <description
8
- >Property Management application for managing properties, tenants, leases, and maintenance requests</description>
9
- <formFactors>Small</formFactors>
10
- <formFactors>Large</formFactors>
11
- <isNavAutoTempTabsDisabled>false</isNavAutoTempTabsDisabled>
12
- <isNavPersonalizationDisabled>false</isNavPersonalizationDisabled>
13
- <isNavTabPersistenceDisabled>false</isNavTabPersistenceDisabled>
14
- <label>Property Management</label>
15
- <navType>Standard</navType>
16
- <tabs>standard-home</tabs>
17
- <tabs>Property__c</tabs>
18
- <tabs>Application__c</tabs>
19
- <tabs>Maintenance_Request__c</tabs>
20
- <tabs>Maintenance_Worker__c</tabs>
21
- <tabs>Tenant__c</tabs>
22
- <tabs>Notification__c</tabs>
23
- <tabs>standard-report</tabs>
24
- <tabs>standard-Dashboard</tabs>
25
- <uiType>Lightning</uiType>
26
- </CustomApplication>