@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.
- package/dist/CHANGELOG.md +16 -0
- package/dist/force-app/main/default/data/Agent__c.json +79 -0
- package/dist/force-app/main/default/data/Application__c.json +10 -10
- package/dist/force-app/main/default/data/Contact.json +44 -0
- package/dist/force-app/main/default/data/Maintenance_Request__c.json +30 -30
- package/dist/force-app/main/default/data/Property__c.json +25 -25
- package/dist/force-app/main/default/data/data-plan.json +13 -1
- package/dist/force-app/main/default/objects/Agent__c/Agent__c.object-meta.xml +66 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/Agent_Type__c.field-meta.xml +37 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/Availability__c.field-meta.xml +37 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/Emergency_Alt__c.field-meta.xml +11 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/Language__c.field-meta.xml +42 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/License_Expiry__c.field-meta.xml +11 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/License_Number__c.field-meta.xml +14 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/Office_Location__c.field-meta.xml +42 -0
- package/dist/force-app/main/default/objects/Agent__c/fields/Territory__c.field-meta.xml +42 -0
- package/dist/force-app/main/default/objects/Maintenance_Request__c/fields/User__c.field-meta.xml +1 -1
- package/dist/force-app/main/default/objects/Property__c/fields/Agent__c.field-meta.xml +1 -1
- package/dist/force-app/main/default/permissionsets/Property_Management_Access.permissionset-meta.xml +53 -25
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/package-lock.json +18307 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/package.json +9 -7
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/applications.ts +142 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/dashboard.ts +1 -2
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/maintenance.ts +63 -6
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/properties.ts +1 -2
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/appLayout.tsx +4 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/AgentforceConversationClient.tsx +127 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ApplicationDetailsModal.tsx +150 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ApplicationsTable.tsx +105 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/MaintenanceDetailsModal.tsx +191 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/PropertyDetailsModal.tsx +274 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/StatusBadge.tsx +17 -17
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/TopBar.tsx +37 -7
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/VerticalNav.tsx +1 -5
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/index.ts +6 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/lib/types.ts +6 -2
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Applications.tsx +129 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Home.tsx +28 -13
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Maintenance.tsx +95 -62
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Properties.tsx +22 -2
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/TestAccPage.tsx +19 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/routes.tsx +12 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/types/conversation.ts +21 -0
- package/dist/package.json +1 -1
- package/package.json +2 -4
- package/dist/force-app/main/default/applications/Property_Management.app-meta.xml +0 -26
- package/dist/force-app/main/default/tabs/Application__c.tab-meta.xml +0 -6
- package/dist/force-app/main/default/tabs/Maintenance_Request__c.tab-meta.xml +0 -7
- package/dist/force-app/main/default/tabs/Maintenance_Worker__c.tab-meta.xml +0 -6
- package/dist/force-app/main/default/tabs/Notification__c.tab-meta.xml +0 -6
- package/dist/force-app/main/default/tabs/Property__c.tab-meta.xml +0 -7
- package/dist/force-app/main/default/tabs/Tenant__c.tab-meta.xml +0 -7
- package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/utils.ts +0 -4
package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/VerticalNav.tsx
CHANGED
|
@@ -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: "/
|
|
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:
|
|
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:
|
|
27
|
+
status: string;
|
|
24
28
|
assignedWorker?: string;
|
|
25
29
|
scheduledDateTime?: string;
|
|
26
30
|
description: string;
|
package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Applications.tsx
ADDED
|
@@ -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
|
|
73
|
-
const
|
|
74
|
-
totalProperties
|
|
75
|
-
unitsAvailable
|
|
76
|
-
occupiedUnits
|
|
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
|
|
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:
|
|
143
|
+
value: trends.totalProperties.trend,
|
|
129
144
|
isPositive: true,
|
|
130
145
|
}}
|
|
131
|
-
subtitle={`Last month total ${
|
|
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:
|
|
152
|
+
value: trends.unitsAvailable.trend,
|
|
138
153
|
isPositive: false,
|
|
139
154
|
}}
|
|
140
|
-
subtitle={`Last month total ${
|
|
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:
|
|
161
|
+
value: trends.occupiedUnits.trend,
|
|
147
162
|
isPositive: true,
|
|
148
163
|
}}
|
|
149
|
-
subtitle={`Last month total ${
|
|
164
|
+
subtitle={`Last month total ${trends.occupiedUnits.previous}`}
|
|
150
165
|
/>
|
|
151
166
|
</div>
|
|
152
167
|
|
package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Maintenance.tsx
CHANGED
|
@@ -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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
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-
|
|
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
|
);
|
package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Properties.tsx
CHANGED
|
@@ -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
|
-
|
|
50
|
-
|
|
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
|
);
|
package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/TestAccPage.tsx
ADDED
|
@@ -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
|
}
|
package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/types/conversation.ts
ADDED
|
@@ -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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-app-react-sample-b2e-experimental",
|
|
3
|
-
"version": "1.
|
|
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
|
-
"
|
|
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>
|