Capstone Reference Implementation: Components and UI
By the end of this lesson, you'll be able to:
- Implement the planned component tree with proper parent/child composition
- Wire the datatable, account summary, and modal to the Apex layer built in Lesson 2
- Apply responsive, mobile-ready layout from the start
Prerequisites: "Capstone Reference Implementation: Data Layer and Apex"
The Parent: commandCenter
import { LightningElement, wire } from 'lwc';
import getOpenCases from '@salesforce/apex/CommandCenterController.getOpenCases';
import NewCaseModal from 'c/newCaseModal';
export default class CommandCenter extends LightningElement {
wiredCasesResult;
selectedAccountId;
@wire(getOpenCases)
wiredCases(result) {
this.wiredCasesResult = result;
}
get cases() {
return this.wiredCasesResult?.data ?? [];
}
handleCaseSelected(event) {
this.selectedAccountId = event.detail.accountId;
}
async handleNewCase() {
const result = await NewCaseModal.open({ size: 'small' });
if (result === 'created') {
await refreshApex(this.wiredCasesResult);
}
}
}
<div class="slds-grid slds-wrap slds-gutters">
<div class="slds-col slds-size_1-of-1 slds-large-size_2-of-3">
<c-case-list cases={cases} oncaseselected={handleCaseSelected}></c-case-list>
</div>
<div class="slds-col slds-size_1-of-1 slds-large-size_1-of-3">
<c-account-summary account-id={selectedAccountId}></c-account-summary>
</div>
</div>
<lightning-button label="New Case" onclick={handleNewCase}></lightning-button>
The parent owns the shared getOpenCases wire and the selectedAccountId state, passing it down to c-account-summary (Module 5's @api pattern) — the SLDS grid (Module 9) stacks to one column on mobile, two-thirds/one-third on large screens.
The Child: caseList
import { LightningElement, api } from 'lwc';
import updateCaseStatus from '@salesforce/apex/CommandCenterController.updateCaseStatus';
const COLUMNS = [
{ label: 'Subject', fieldName: 'subject', type: 'text' },
{ label: 'Status', fieldName: 'status', type: 'text', editable: true },
];
export default class CaseList extends LightningElement {
@api cases;
columns = COLUMNS;
draftValues = [];
handleRowClick(event) {
this.dispatchEvent(new CustomEvent('caseselected', {
detail: { accountId: event.detail.row.accountId },
}));
}
async handleSave(event) {
const draftValues = event.detail.draftValues;
await Promise.all(draftValues.map(draft =>
updateCaseStatus({ caseId: draft.caseId, newStatus: draft.status })
));
this.draftValues = [];
}
}
caseselected (Module 5's CustomEvent pattern) tells the parent which Account to show a summary for; inline editing (Module 10) and Promise.all bulk-persist status changes exactly as in Module 19's Case Management project.
The Child: accountSummary
import { LightningElement, api, wire } from 'lwc';
import getAccountSummary from '@salesforce/apex/CommandCenterController.getAccountSummary';
export default class AccountSummary extends LightningElement {
@api accountId;
@wire(getAccountSummary, { accountId: '$accountId' })
summary;
}
The reactive '$accountId' parameter (Module 6) means simply changing the parent's selectedAccountId automatically re-fetches the right Account's summary — no manual refresh call needed for this piece.
Exercise
Explain, as a comment, why caseselected is dispatched as a CustomEvent rather than accountSummary querying the selected Case directly.
Show hint
Recall Module 5's child-to-parent communication rationale.
Exercise
Challenge: explain, as a comment, why accountId is a reactive ($-prefixed) wire parameter in accountSummary.
Show hint
Recall Module 6's reactive parameter lesson.
Capstone Reference Implementation: Components and UI Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
The component tree planned in Lesson 1 becomes real markup and JavaScript — a datatable-driven Case list, an LDS-style Account summary, and a modal for creating new Cases, laid out responsively from the start.