feat(loyalty): add staff autocomplete to PIN management
When creating or editing a staff PIN in the store context, the name field now shows an autocomplete dropdown with the store's team members (loaded from GET /store/team/members). Selecting a member auto-fills name and staff_id (email). The dropdown filters as you type. Only active in store context (where staffApiPrefix is configured). Merchant and admin PIN views are unaffected — merchant has no staffApiPrefix, admin is read-only. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ function loyaltyPinsList(config) {
|
||||
pins: [],
|
||||
program: null,
|
||||
locations: [],
|
||||
staffMembers: [],
|
||||
|
||||
// Filters
|
||||
filters: {
|
||||
@@ -57,6 +58,33 @@ function loyaltyPinsList(config) {
|
||||
store_id: ''
|
||||
},
|
||||
|
||||
// Staff autocomplete state
|
||||
staffSearch: '',
|
||||
showStaffDropdown: false,
|
||||
|
||||
get filteredStaff() {
|
||||
if (!this.staffSearch) return this.staffMembers;
|
||||
const q = this.staffSearch.toLowerCase();
|
||||
return this.staffMembers.filter(m =>
|
||||
(m.full_name && m.full_name.toLowerCase().includes(q)) ||
|
||||
(m.email && m.email.toLowerCase().includes(q))
|
||||
);
|
||||
},
|
||||
|
||||
selectStaffMember(member) {
|
||||
this.pinForm.name = member.full_name;
|
||||
this.pinForm.staff_id = member.email;
|
||||
this.staffSearch = member.full_name;
|
||||
this.showStaffDropdown = false;
|
||||
},
|
||||
|
||||
clearStaffSelection() {
|
||||
this.staffSearch = '';
|
||||
this.pinForm.name = '';
|
||||
this.pinForm.staff_id = '';
|
||||
this.showStaffDropdown = false;
|
||||
},
|
||||
|
||||
// Action state
|
||||
saving: false,
|
||||
deleting: false,
|
||||
@@ -88,6 +116,9 @@ function loyaltyPinsList(config) {
|
||||
if (config.showStoreFilter) {
|
||||
parallel.push(this.loadLocations());
|
||||
}
|
||||
if (config.showCrud && config.staffApiPrefix) {
|
||||
parallel.push(this.loadStaffMembers());
|
||||
}
|
||||
await Promise.all(parallel);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -137,6 +168,18 @@ function loyaltyPinsList(config) {
|
||||
}
|
||||
},
|
||||
|
||||
async loadStaffMembers() {
|
||||
try {
|
||||
const response = await apiClient.get(config.staffApiPrefix + '/team/members');
|
||||
if (response && response.members) {
|
||||
this.staffMembers = response.members.filter(m => m.is_active);
|
||||
loyaltyPinsListLog.info('Loaded', this.staffMembers.length, 'staff members');
|
||||
}
|
||||
} catch (error) {
|
||||
loyaltyPinsListLog.warn('Failed to load staff members:', error.message);
|
||||
}
|
||||
},
|
||||
|
||||
computeStats() {
|
||||
this.stats.total = this.pins.length;
|
||||
this.stats.active = this.pins.filter(p => p.is_active && !p.is_locked).length;
|
||||
@@ -156,6 +199,8 @@ function loyaltyPinsList(config) {
|
||||
pin: '',
|
||||
store_id: ''
|
||||
};
|
||||
this.staffSearch = '';
|
||||
this.showStaffDropdown = false;
|
||||
this.showCreateModal = true;
|
||||
},
|
||||
|
||||
@@ -167,6 +212,8 @@ function loyaltyPinsList(config) {
|
||||
pin: '',
|
||||
store_id: pin.store_id || ''
|
||||
};
|
||||
this.staffSearch = pin.name || '';
|
||||
this.showStaffDropdown = false;
|
||||
this.showEditModal = true;
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user