@dcrackel/hematournamentui 1.0.712 → 1.0.714
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/.prettierignore +7 -7
- package/.storybook/main.js +3 -1
- package/README.md +42 -0
- package/dist/HemaTournamentUI-lib.es.js +6856 -6243
- package/dist/HemaTournamentUI-lib.umd.js +27 -27
- package/dist/hematournamentui-tailwind.css +79 -9
- package/package.json +96 -96
- package/prettier.config.js +16 -16
- package/src/index.js +43 -42
- package/src/main.js +1 -1
- package/src/mocks/getDEBouts-TableOf128.js +37 -37
- package/src/mocks/getDEBouts-TableOf64.js +35 -35
- package/src/stories/Atoms/Input/BaseInput.test.js +97 -97
- package/src/stories/Atoms/Input/BaseInput.vue +149 -149
- package/src/stories/Molecules/Indicators/MissingHemaRatingsId/MissingHemaRatingsId.stories.js +23 -23
- package/src/stories/Molecules/Indicators/MissingHemaRatingsId/MissingHemaRatingsId.vue +35 -35
- package/src/stories/Molecules/Indicators/RegistrationStatus/RegistrationStatus.vue +30 -30
- package/src/stories/Molecules/Menus/HoverActions/HoverActions.test.js +138 -0
- package/src/stories/Molecules/Menus/HoverActions/HoverActions.vue +212 -0
- package/src/stories/Molecules/Modals/BracketDirectorsModal/BracketDirectorsModal.stories.js +49 -0
- package/src/stories/Molecules/Modals/BracketDirectorsModal/BracketDirectorsModal.test.js +129 -0
- package/src/stories/Molecules/Modals/BracketDirectorsModal/BracketDirectorsModal.vue +165 -0
- package/src/stories/Molecules/Modals/DirectorModal/DirectorModal.stories.js +6 -0
- package/src/stories/Molecules/Modals/DirectorModal/DirectorModal.test.js +18 -18
- package/src/stories/Molecules/Modals/DirectorModal/DirectorModal.vue +1 -1
- package/src/stories/Organisms/Cards/BoutCard/BoutCard.vue +5 -1
- package/src/stories/Organisms/Cards/BoutCard/Variants/BoutCardActive/BoutCardActive.vue +19 -10
- package/src/stories/Organisms/Cards/BoutCard/Variants/BoutCardInactive/BoutCardInactive.vue +11 -7
- package/src/stories/Organisms/Cards/BracketDirectorAssignmentCard/BracketDirectorAssignmentCard.stories.js +42 -33
- package/src/stories/Organisms/Cards/BracketDirectorAssignmentCard/BracketDirectorAssignmentCard.test.js +76 -45
- package/src/stories/Organisms/Cards/BracketDirectorAssignmentCard/BracketDirectorAssignmentCard.vue +122 -103
- package/src/stories/Organisms/Cards/Director/DirectorCard.test.js +82 -0
- package/src/stories/Organisms/Cards/Director/DirectorCard.vue +32 -51
- package/src/stories/Organisms/Cards/EditBout/EditBout.test.js +51 -51
- package/src/stories/Organisms/Cards/EventCard/EventCard.test.js +106 -106
- package/src/stories/Organisms/Cards/FencerCard/FencerCard.vue +298 -298
- package/src/stories/Organisms/Cards/TableauBoutCard/TableauBoutCard.stories.js +77 -60
- package/src/stories/Organisms/Cards/TableauBoutCard/TableauBoutCard.test.js +144 -143
- package/src/stories/Organisms/Cards/TableauBoutCard/TableauBoutCard.vue +289 -256
- package/src/stories/Organisms/Cards/TableauFencerCard/TableauFencerCard.stories.js +69 -69
- package/src/stories/Organisms/Cards/TableauFencerCard/TableauFencerCard.vue +80 -80
- package/src/stories/Organisms/Cards/WaitlistFencerCard/WaitlistFencerCard.vue +153 -153
- package/src/stories/Organisms/ComplexInputs/DropDown/DropDownMenu.vue +4 -0
- package/src/stories/Organisms/ComplexInputs/ImageCropper/ImageCropper.stories.js +31 -31
- package/src/stories/Organisms/ComplexInputs/ImageCropper/ImageCropper.test.js +109 -109
- package/src/stories/Organisms/ComplexInputs/ImageCropper/ImageCropper.vue +192 -192
- package/src/stories/Organisms/Containers/Tableau/Tableau.stories.js +1 -0
- package/src/stories/Organisms/Containers/Tableau/Tableau.test.js +247 -204
- package/src/stories/Organisms/Containers/Tableau/Tableau.vue +89 -15
- package/src/stories/Organisms/Containers/Tableau/components/BracketDirectorAssignmentPanel.test.js +51 -29
- package/src/stories/Organisms/Containers/Tableau/components/BracketDirectorAssignmentPanel.vue +63 -46
- package/src/stories/Organisms/Containers/Tableau/components/TableauSvgOverlay.test.js +21 -21
- package/src/stories/Organisms/Containers/Tableau/components/TableauSvgOverlay.vue +39 -39
- package/src/stories/Organisms/Containers/Tableau/layout/TableauLayoutEngine.js +145 -145
- package/src/stories/Organisms/Containers/Tableau/layout/TableauLayoutEngine.test.js +64 -64
- package/src/stories/Organisms/Containers/Tableau/plannedAssignments.js +36 -57
- package/src/stories/Organisms/Containers/Tableau/plannedAssignments.test.js +101 -65
- package/src/stories/Organisms/Containers/TableauColumn/TableauColumn.vue +14 -1
- package/src/stories/Organisms/Wizards/EditEventWizard/BasicEventInfo/BasicEventInfo.stories.js +52 -52
- package/src/stories/Organisms/Wizards/EditEventWizard/BasicEventInfo/BasicEventInfo.vue +10 -3
- package/src/stories/Organisms/Wizards/EditEventWizard/DirectElimination/DirectElimination.vue +226 -226
- package/src/stories/Organisms/Wizards/EditEventWizard/DirectEliminationPromotion/DirectEliminationPromotion.vue +204 -204
- package/src/stories/Organisms/Wizards/EditEventWizard/EditEventWizard.stories.js +137 -137
- package/src/stories/Organisms/Wizards/EditEventWizard/EventCustomization/EventCustomization.vue +172 -172
- package/src/stories/Organisms/Wizards/EditEventWizard/PoolConfiguration/PoolConfiguration.vue +216 -216
- package/src/stories/Organisms/Wizards/EditEventWizard/PriceFields.test.js +79 -79
- package/src/stories/Organisms/Wizards/EditEventWizard/RuleSerialization.test.js +29 -29
- package/src/stories/Organisms/Wizards/EditEventWizard/WeaponSelection.test.js +138 -0
- package/src/stories/Templates/EventManagement/Bracket/Bracket.stories.js +149 -9
- package/src/stories/Templates/EventManagement/Bracket/Bracket.test.js +54 -2
- package/src/stories/Templates/EventManagement/Bracket/Bracket.vue +77 -8
- package/src/stories/Templates/EventManagement/Bracket/BracketDirectorAssignment.test.js +242 -0
- package/src/stories/Templates/EventManagement/Bracket/BracketMobile.test.js +131 -0
- package/src/stories/Templates/EventManagement/Bracket/BracketPlannedSuggestions.js +50 -39
- package/src/stories/Templates/EventManagement/Bracket/BracketStories.test.js +201 -0
- package/src/stories/Templates/EventManagement/Bracket/BracketStoryAssignments.js +93 -0
- package/src/stories/Templates/EventManagement/Bracket/BracketStoryAssignments.test.js +152 -0
- package/src/stories/Templates/EventManagement/Bracket/BracketStoryHarness.js +39 -39
- package/src/stories/Templates/EventManagement/Bracket/BracketStoryHarness.test.js +79 -79
- package/src/stories/Templates/EventManagement/EditEventInfo/EditEventInfo.stories.js +93 -93
- package/src/stories/Templates/EventManagement/EditEventInfo/EditEventInfo.vue +91 -91
- package/src/stories/Templates/EventManagement/PoolLive/PoolLive.test.js +121 -121
- package/src/stories/Templates/Menus/EditEventsTopMenu/EditEventsTopMenu.stories.js +9 -2
- package/src/stories/Templates/Menus/EditEventsTopMenu/EditEventsTopMenu.vue +5 -4
- package/src/stories/Templates/PersonManagement/Admin/Administration/Administration.stories.js +81 -81
- package/src/stories/Templates/PersonManagement/Admin/Administration/Administration.test.js +39 -39
- package/src/stories/Templates/PersonManagement/Admin/Administration/Administration.vue +101 -101
- package/src/stories/Templates/PersonManagement/Admin/FencerAdmin/FencerAdmin.stories.js +71 -71
- package/src/stories/Templates/PersonManagement/Admin/FencerAdmin/FencerAdmin.vue +86 -86
- package/src/stories/Templates/PersonManagement/Admin/MergeAccounts/MergeAccounts.stories.js +86 -86
- package/src/stories/Templates/PersonManagement/Admin/MergeAccounts/MergeAccounts.vue +247 -247
- package/src/stories/Templates/PersonManagement/Basic/BasicEdit.vue +170 -170
- package/src/stories/Templates/PersonManagement/PersonManagement.stories.js +156 -156
- package/src/stories/Templates/PersonManagement/PersonManagement.test.js +329 -329
- package/src/stories/Templates/PersonManagement/PersonManagement.vue +329 -329
- package/src/stories/Templates/PersonManagement/PersonManagementDraft.js +42 -42
- package/src/stories/Templates/TournamentManagement/TournamentManagement.stories.js +84 -84
- package/src/stories/Templates/TournamentManagement/TournamentManagement.test.js +114 -114
- package/src/stories/Templates/TournamentManagement/TournamentManagement.vue +363 -363
- package/src/stories/Templates/TournamentManagement/TournamentPageOne/TournamentPageOne.stories.js +116 -116
- package/src/stories/Templates/TournamentManagement/TournamentPageOne/TournamentPageOne.vue +307 -307
- package/src/stories/Util/Validations/PersonManagementValidations.js +45 -45
- package/src/stories/Util/Validations/PriceValidation.js +6 -6
- package/src/stories/Util/boutDirectorAssignment.js +46 -0
- package/src/stories/Util/bracketDirectors.js +86 -0
- package/src/stories/Util/registrationStatus.js +11 -11
- package/src/stories/Util/tabs.js +19 -47
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import BasicEventInfo from './BasicEventInfo/BasicEventInfo.vue';
|
|
4
|
+
import EditEventWizard from './EditEventWizard.vue';
|
|
5
|
+
import DropDownMenu from '../../ComplexInputs/DropDown/DropDownMenu.vue';
|
|
6
|
+
|
|
7
|
+
const wrappers = [];
|
|
8
|
+
const weapons = [
|
|
9
|
+
{ text: 'Sword & Buckler', link: 8 },
|
|
10
|
+
{ text: 'MG Longsword', link: 17 },
|
|
11
|
+
{ text: 'Longsword', link: 1 }
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
afterEach(() => wrappers.splice(0).forEach(wrapper => wrapper.unmount()));
|
|
15
|
+
|
|
16
|
+
function mountBasic(eventConfig, options = weapons) {
|
|
17
|
+
const wrapper = mount(BasicEventInfo, {
|
|
18
|
+
props: {
|
|
19
|
+
eventConfig,
|
|
20
|
+
weapons: options,
|
|
21
|
+
validation: { EventName: { invalid: false } },
|
|
22
|
+
steps: [],
|
|
23
|
+
currentStep: 0
|
|
24
|
+
},
|
|
25
|
+
global: { stubs: { DatePicker: true, StepIndicator: true } }
|
|
26
|
+
});
|
|
27
|
+
wrappers.push(wrapper);
|
|
28
|
+
return wrapper;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function selectedText(wrapper) {
|
|
32
|
+
return wrapper.findComponent(DropDownMenu).find('input').element.value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('event weapon selection', () => {
|
|
36
|
+
it.each([1, '1', 8, '8', 17, '17'])('shows the actual saved weapon for ID %s without emitting a change', WeaponId => {
|
|
37
|
+
const wrapper = mountBasic({ WeaponId });
|
|
38
|
+
expect(selectedText(wrapper)).toBe(weapons.find(option => String(option.link) === String(WeaponId)).text);
|
|
39
|
+
expect(wrapper.emitted('update')).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('accepts raw weapon records as well as dropdown options', () => {
|
|
43
|
+
const wrapper = mountBasic(
|
|
44
|
+
{ WeaponId: '8' },
|
|
45
|
+
weapons.map(option => ({ Id: option.link, Name: option.text }))
|
|
46
|
+
);
|
|
47
|
+
expect(selectedText(wrapper)).toBe('Sword & Buckler');
|
|
48
|
+
expect(wrapper.findComponent(DropDownMenu).props('items')).toEqual(
|
|
49
|
+
weapons.map(option => ({ ...option, Id: option.link, Name: option.text }))
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it.each([undefined, 99])('does not pretend an unavailable weapon %s is Longsword', WeaponId => {
|
|
54
|
+
const wrapper = mountBasic({ WeaponId });
|
|
55
|
+
expect(selectedText(wrapper)).toBe('Select a weapon');
|
|
56
|
+
expect(wrapper.emitted('update')).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('reconciles a parent weapon change and restores that selection after closing the menu', async () => {
|
|
60
|
+
const wrapper = mountBasic({ WeaponId: 8 });
|
|
61
|
+
await wrapper.setProps({ eventConfig: { WeaponId: 1 } });
|
|
62
|
+
expect(selectedText(wrapper)).toBe('Longsword');
|
|
63
|
+
const dropdown = wrapper.findComponent(DropDownMenu);
|
|
64
|
+
dropdown.vm.clearInput();
|
|
65
|
+
dropdown.vm.restorePreviousValue();
|
|
66
|
+
await wrapper.vm.$nextTick();
|
|
67
|
+
expect(selectedText(wrapper)).toBe('Longsword');
|
|
68
|
+
expect(wrapper.emitted('update')).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('shows the saved selection when the weapon options arrive later', async () => {
|
|
72
|
+
const wrapper = mountBasic({ WeaponId: 8 }, []);
|
|
73
|
+
await wrapper.setProps({ weapons });
|
|
74
|
+
expect(selectedText(wrapper)).toBe('Sword & Buckler');
|
|
75
|
+
expect(wrapper.emitted('update')).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('emits the chosen option ID only after an explicit selection', async () => {
|
|
79
|
+
const wrapper = mountBasic({ WeaponId: 8 });
|
|
80
|
+
const dropdown = wrapper.findComponent(DropDownMenu);
|
|
81
|
+
dropdown.vm.handleDropDown();
|
|
82
|
+
await wrapper.vm.$nextTick();
|
|
83
|
+
await dropdown
|
|
84
|
+
.findAll('a')
|
|
85
|
+
.find(option => option.text() === 'Longsword')
|
|
86
|
+
.trigger('click');
|
|
87
|
+
expect(wrapper.emitted('update')).toEqual([[{ WeaponId: 1 }]]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('preserves the saved weapon when another field is edited and saves a deliberate weapon change', async () => {
|
|
91
|
+
const event = { EventId: 12, EventName: 'Example Event', EventPrice: 25, WeaponId: '8', rules: [] };
|
|
92
|
+
const wrapper = mount(EditEventWizard, {
|
|
93
|
+
props: { event, weapons, editMode: true },
|
|
94
|
+
global: { stubs: { DatePicker: true, StepIndicator: true } }
|
|
95
|
+
});
|
|
96
|
+
wrappers.push(wrapper);
|
|
97
|
+
await wrapper.vm.$nextTick();
|
|
98
|
+
expect(selectedText(wrapper)).toBe('Sword & Buckler');
|
|
99
|
+
wrapper.vm.handleValueChange({ EventName: 'Renamed Event' });
|
|
100
|
+
wrapper.vm.handleUpdate();
|
|
101
|
+
expect(wrapper.emitted('save:step')[0][0].event.WeaponId).toBe('8');
|
|
102
|
+
|
|
103
|
+
wrapper.findComponent(DropDownMenu).vm.handleClick(weapons.find(option => option.link === 17));
|
|
104
|
+
await wrapper.vm.$nextTick();
|
|
105
|
+
wrapper.vm.handleUpdate();
|
|
106
|
+
expect(wrapper.emitted('save:step')[1][0].event.WeaponId).toBe(17);
|
|
107
|
+
expect(event.WeaponId).toBe('8');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it.each([false, true])(
|
|
112
|
+
'actual dropdown choices retain catalog IDs through submit with edit mode %s',
|
|
113
|
+
async editMode => {
|
|
114
|
+
const event = { EventId: 230, EventName: 'MG Longsword', EventPrice: 45, WeaponId: 17, rules: [] };
|
|
115
|
+
const wrapper = mount(EditEventWizard, {
|
|
116
|
+
props: { event, weapons, editMode },
|
|
117
|
+
global: { stubs: { DatePicker: true, StepIndicator: true } }
|
|
118
|
+
});
|
|
119
|
+
wrappers.push(wrapper);
|
|
120
|
+
await wrapper.vm.$nextTick();
|
|
121
|
+
expect(selectedText(wrapper)).toBe('MG Longsword');
|
|
122
|
+
for (const option of weapons) {
|
|
123
|
+
const dropdown = wrapper.findComponent(DropDownMenu);
|
|
124
|
+
dropdown.vm.handleDropDown();
|
|
125
|
+
await wrapper.vm.$nextTick();
|
|
126
|
+
await dropdown
|
|
127
|
+
.findAll('a')
|
|
128
|
+
.find(item => item.text() === option.text)
|
|
129
|
+
.trigger('click');
|
|
130
|
+
expect(selectedText(wrapper)).toBe(option.text);
|
|
131
|
+
wrapper.vm.handleSubmit();
|
|
132
|
+
const eventName = editMode ? 'save:step' : 'update:submit';
|
|
133
|
+
const submitted = wrapper.emitted(eventName).at(-1)[0];
|
|
134
|
+
expect((editMode ? submitted.event : submitted).WeaponId).toBe(option.link);
|
|
135
|
+
}
|
|
136
|
+
expect(event.WeaponId).toBe(17);
|
|
137
|
+
}
|
|
138
|
+
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ref, watch } from 'vue';
|
|
1
|
+
import { computed, nextTick, ref, watch } from 'vue';
|
|
2
2
|
import Bracket from './Bracket.vue';
|
|
3
|
+
import { distributeStoryAssignments } from './BracketStoryAssignments.js';
|
|
3
4
|
import {
|
|
4
5
|
activateStoryBout,
|
|
5
6
|
canStoryDirectorDirectBout,
|
|
@@ -9,7 +10,8 @@ import {
|
|
|
9
10
|
replaceStoryBout
|
|
10
11
|
} from './BracketStoryHarness.js';
|
|
11
12
|
import {
|
|
12
|
-
|
|
13
|
+
availableDirectors,
|
|
14
|
+
availableRings,
|
|
13
15
|
plannedDirectingStations,
|
|
14
16
|
plannedSuggestionViewerId
|
|
15
17
|
} from './BracketPlannedSuggestions.js';
|
|
@@ -30,11 +32,55 @@ const renderInteractiveBracket = args => ({
|
|
|
30
32
|
setup() {
|
|
31
33
|
const storyBouts = ref(cloneStoryBouts(args.bouts));
|
|
32
34
|
const storyStations = ref(cloneStations(args.plannedDirectingStations));
|
|
35
|
+
const storyAssignments = ref([]);
|
|
36
|
+
const canAddDirector = computed(() =>
|
|
37
|
+
(args.availableDirectors || availableDirectors).some(
|
|
38
|
+
director =>
|
|
39
|
+
!storyStations.value.some(station => String(station.Director?.PersonId) === String(director.PersonId))
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
const redistributeAssignments = () => {
|
|
43
|
+
storyAssignments.value = distributeStoryAssignments({
|
|
44
|
+
bouts: storyBouts.value,
|
|
45
|
+
stations: storyStations.value,
|
|
46
|
+
previousAssignments: storyAssignments.value
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const applyProvidedAssignments = assignments => {
|
|
50
|
+
redistributeAssignments();
|
|
51
|
+
const providedIds = new Set(assignments.map(assignment => String(assignment.DEBoutId)));
|
|
52
|
+
storyAssignments.value = [
|
|
53
|
+
...storyAssignments.value.filter(assignment => !providedIds.has(String(assignment.DEBoutId))),
|
|
54
|
+
...assignments.map(assignment => ({ ...assignment }))
|
|
55
|
+
];
|
|
56
|
+
};
|
|
57
|
+
const assignmentBout = ref(null);
|
|
58
|
+
const directorPicker = ref(null);
|
|
59
|
+
const assignmentDialog = ref(null);
|
|
60
|
+
|
|
61
|
+
watch(() => args.plannedBoutAssignments, applyProvidedAssignments, { deep: true, immediate: true });
|
|
62
|
+
|
|
63
|
+
const requestBoutDirector = async bout => {
|
|
64
|
+
assignmentBout.value = bout;
|
|
65
|
+
await nextTick();
|
|
66
|
+
assignmentDialog.value?.showModal();
|
|
67
|
+
directorPicker.value?.focus();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const assignPlannedDirector = ringId => {
|
|
71
|
+
const bout = assignmentBout.value;
|
|
72
|
+
const station = storyStations.value.find(item => String(item.RingId) === String(ringId));
|
|
73
|
+
if (!bout || !station) return;
|
|
74
|
+
const remaining = storyAssignments.value.filter(item => String(item.DEBoutId) !== String(bout.DEBoutId));
|
|
75
|
+
storyAssignments.value = [...remaining, { DEBoutId: bout.DEBoutId, RingId: station.RingId }];
|
|
76
|
+
assignmentBout.value = null;
|
|
77
|
+
};
|
|
33
78
|
|
|
34
79
|
watch(
|
|
35
80
|
() => args.bouts,
|
|
36
81
|
bouts => {
|
|
37
82
|
storyBouts.value = cloneStoryBouts(bouts);
|
|
83
|
+
redistributeAssignments();
|
|
38
84
|
},
|
|
39
85
|
{ deep: true }
|
|
40
86
|
);
|
|
@@ -43,6 +89,7 @@ const renderInteractiveBracket = args => ({
|
|
|
43
89
|
() => args.plannedDirectingStations,
|
|
44
90
|
stations => {
|
|
45
91
|
storyStations.value = cloneStations(stations);
|
|
92
|
+
redistributeAssignments();
|
|
46
93
|
},
|
|
47
94
|
{ deep: true }
|
|
48
95
|
);
|
|
@@ -52,13 +99,18 @@ const renderInteractiveBracket = args => ({
|
|
|
52
99
|
};
|
|
53
100
|
|
|
54
101
|
const getViewerStation = () =>
|
|
55
|
-
|
|
102
|
+
[
|
|
103
|
+
...storyStations.value,
|
|
104
|
+
...plannedDirectingStations,
|
|
105
|
+
...(args.availableDirectors || []).map(Director => ({ Director }))
|
|
106
|
+
].find(station => String(station.Director?.PersonId) === String(args.viewerPersonId));
|
|
56
107
|
|
|
57
108
|
const handleAddPlannedDirector = () => {
|
|
58
109
|
const assignedRingIds = new Set(storyStations.value.map(station => String(station.RingId)));
|
|
59
110
|
const nextStation = plannedDirectingStations.find(station => !assignedRingIds.has(String(station.RingId)));
|
|
60
111
|
if (!nextStation) return;
|
|
61
112
|
storyStations.value = [...storyStations.value, ...cloneStations([nextStation])];
|
|
113
|
+
redistributeAssignments();
|
|
62
114
|
};
|
|
63
115
|
|
|
64
116
|
const handleDirectingBout = bout => {
|
|
@@ -75,13 +127,43 @@ const renderInteractiveBracket = args => ({
|
|
|
75
127
|
args,
|
|
76
128
|
storyBouts,
|
|
77
129
|
storyStations,
|
|
130
|
+
storyAssignments,
|
|
131
|
+
canAddDirector,
|
|
132
|
+
assignmentBout,
|
|
133
|
+
directorPicker,
|
|
134
|
+
assignmentDialog,
|
|
135
|
+
requestBoutDirector,
|
|
136
|
+
assignPlannedDirector,
|
|
78
137
|
handleAddPlannedDirector,
|
|
138
|
+
handleRemovePlannedDirector(station) {
|
|
139
|
+
const remainingStations = storyStations.value.filter(item => String(item.RingId) !== String(station?.RingId));
|
|
140
|
+
if (remainingStations.length === storyStations.value.length) return;
|
|
141
|
+
storyStations.value = remainingStations;
|
|
142
|
+
redistributeAssignments();
|
|
143
|
+
},
|
|
144
|
+
handlePlannedDirectorsUpdate(stations) {
|
|
145
|
+
storyStations.value = cloneStations(stations);
|
|
146
|
+
redistributeAssignments();
|
|
147
|
+
},
|
|
79
148
|
handleCloseDirectingBout,
|
|
80
149
|
handleDirectingBout,
|
|
81
150
|
persistStoryBout
|
|
82
151
|
};
|
|
83
152
|
},
|
|
84
153
|
template: `
|
|
154
|
+
<div>
|
|
155
|
+
<dialog v-if="assignmentBout" ref="assignmentDialog" aria-label="Assign director" class="fixed inset-0 m-auto rounded border border-dropdownSelect bg-white p-4 shadow-lg backdrop:bg-black/20" @cancel="assignmentBout = null">
|
|
156
|
+
<label class="text-sm text-primaryHighlight">
|
|
157
|
+
Assign director to bout {{ assignmentBout.DEBoutId }}
|
|
158
|
+
<select ref="directorPicker" class="ml-2 rounded border border-dropdownSelect p-2" @change="assignPlannedDirector($event.target.value)">
|
|
159
|
+
<option value="">Choose director</option>
|
|
160
|
+
<option v-for="station in storyStations" :key="station.RingId" :value="station.RingId">
|
|
161
|
+
{{ station.Director?.DisplayName || 'Director TBD' }} / {{ station.RingName }}
|
|
162
|
+
</option>
|
|
163
|
+
</select>
|
|
164
|
+
</label>
|
|
165
|
+
<button type="button" class="ml-4 text-sm underline" @click="assignmentBout = null">Cancel</button>
|
|
166
|
+
</dialog>
|
|
85
167
|
<Bracket
|
|
86
168
|
v-bind="args"
|
|
87
169
|
:connectedToServer="args.connectedToServer"
|
|
@@ -89,13 +171,19 @@ const renderInteractiveBracket = args => ({
|
|
|
89
171
|
:hostingClubColors="args.hostingClubColors"
|
|
90
172
|
:bouts="storyBouts"
|
|
91
173
|
:plannedDirectingStations="storyStations"
|
|
174
|
+
:plannedBoutAssignments="storyAssignments"
|
|
175
|
+
:showAddPlannedDirectorCard="args.showAddPlannedDirectorCard && canAddDirector"
|
|
176
|
+
@request:bout-director="requestBoutDirector"
|
|
92
177
|
@close:directing-bout="handleCloseDirectingBout"
|
|
93
178
|
@request:add-planned-director="handleAddPlannedDirector"
|
|
179
|
+
@request:remove-planned-director="handleRemovePlannedDirector"
|
|
180
|
+
@update:planned-directing-stations="handlePlannedDirectorsUpdate"
|
|
94
181
|
@update:directing-bout="handleDirectingBout"
|
|
95
182
|
@request:bout-active="handleDirectingBout"
|
|
96
183
|
@update:bout="persistStoryBout"
|
|
97
184
|
@submit:bout="persistStoryBout"
|
|
98
185
|
/>
|
|
186
|
+
</div>
|
|
99
187
|
`
|
|
100
188
|
});
|
|
101
189
|
|
|
@@ -105,18 +193,30 @@ export default {
|
|
|
105
193
|
tags: ['Bracket'],
|
|
106
194
|
render: renderInteractiveBracket,
|
|
107
195
|
args: {
|
|
196
|
+
availableDirectors,
|
|
197
|
+
rings: availableRings,
|
|
108
198
|
bouts: getDEWithBouts.pools[0].Bouts,
|
|
109
199
|
eventRules: getDEWithBouts.eventRules,
|
|
110
200
|
hostingClubColors: getDEWithBouts.hostingClubColors,
|
|
111
201
|
connectedToServer: true,
|
|
112
202
|
role: 'admin',
|
|
113
|
-
plannedDirectingStations:
|
|
203
|
+
plannedDirectingStations: plannedDirectingStations.slice(0, 2),
|
|
114
204
|
plannedBoutAssignments: [],
|
|
115
|
-
viewerPersonId:
|
|
116
|
-
showPlannedDirectorAssignments:
|
|
117
|
-
showAddPlannedDirectorCard: true
|
|
205
|
+
viewerPersonId: plannedSuggestionViewerId,
|
|
206
|
+
showPlannedDirectorAssignments: true,
|
|
207
|
+
showAddPlannedDirectorCard: true,
|
|
208
|
+
showBoutDirectorAssignment: true
|
|
118
209
|
},
|
|
119
210
|
argTypes: {
|
|
211
|
+
availableDirectors: {
|
|
212
|
+
control: 'object',
|
|
213
|
+
description: 'Eligible staff, including DE-only directors, supplied by the parent.'
|
|
214
|
+
},
|
|
215
|
+
rings: { control: 'object', description: 'Available rings supplied by the parent.' },
|
|
216
|
+
showBoutDirectorAssignment: {
|
|
217
|
+
control: 'boolean',
|
|
218
|
+
description: 'Include Assign director in the pairing hover menu. The parent supplies staff selection and saving.'
|
|
219
|
+
},
|
|
120
220
|
bouts: {
|
|
121
221
|
control: 'object'
|
|
122
222
|
},
|
|
@@ -220,10 +320,38 @@ export const PlannedDirectorSuggestions = {
|
|
|
220
320
|
status: 'de',
|
|
221
321
|
role: 'Admin',
|
|
222
322
|
plannedDirectingStations: plannedDirectingStations.slice(0, 2),
|
|
223
|
-
plannedBoutAssignments,
|
|
224
323
|
viewerPersonId: plannedSuggestionViewerId,
|
|
225
324
|
showPlannedDirectorAssignments: true,
|
|
226
|
-
showAddPlannedDirectorCard: true
|
|
325
|
+
showAddPlannedDirectorCard: true,
|
|
326
|
+
showBoutDirectorAssignment: true
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
export const ThreeDirectors = {
|
|
331
|
+
args: { ...PlannedDirectorSuggestions.args, plannedDirectingStations: plannedDirectingStations.slice(0, 3) }
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
export const FourDirectors = {
|
|
335
|
+
args: { ...PlannedDirectorSuggestions.args, plannedDirectingStations: plannedDirectingStations.slice(0, 4) }
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
export const FiveDirectors = {
|
|
339
|
+
args: { ...PlannedDirectorSuggestions.args, plannedDirectingStations: plannedDirectingStations.slice(0, 5) }
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
export const SixDirectors = {
|
|
343
|
+
args: { ...PlannedDirectorSuggestions.args, plannedDirectingStations }
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
export const HoverBoutActions = {
|
|
347
|
+
args: { ...PlannedDirectorSuggestions.args },
|
|
348
|
+
parameters: {
|
|
349
|
+
docs: {
|
|
350
|
+
description: {
|
|
351
|
+
story:
|
|
352
|
+
'Hover over a pairing for Open bout and Assign director. Clicking the pairing still opens it directly. The picker in this story simulates the consuming app; the story simulates balanced section coverage through the semifinals, while production assignment and persistence remain app-owned.'
|
|
353
|
+
}
|
|
354
|
+
}
|
|
227
355
|
}
|
|
228
356
|
};
|
|
229
357
|
|
|
@@ -246,3 +374,15 @@ export const noBoutsYet = {
|
|
|
246
374
|
status: 'live'
|
|
247
375
|
}
|
|
248
376
|
};
|
|
377
|
+
|
|
378
|
+
export const PhoneDirector = {
|
|
379
|
+
args: { ...PlannedDirectorSuggestions.args, role: 'Director' },
|
|
380
|
+
parameters: {
|
|
381
|
+
docs: {
|
|
382
|
+
description: {
|
|
383
|
+
story:
|
|
384
|
+
'Use a viewport narrower than 768px to see the phone directing view: a bout list, ring suggestions, connection status, and collapsed completed bouts. Organising controls stay on desktop, even when assignment options are enabled. Returning to desktop restores the selected List View or Tableau.'
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
@@ -157,10 +157,62 @@ describe('Bracket bout interaction', () => {
|
|
|
157
157
|
expect(wrapper.emitted('request:add-planned-director')).toEqual([[]]);
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
-
it('does not render planned directing controls when
|
|
161
|
-
const wrapper = mountBracket(
|
|
160
|
+
it('does not render planned directing controls when explicitly disabled', () => {
|
|
161
|
+
const wrapper = mountBracket(undefined, {
|
|
162
|
+
showPlannedDirectorAssignments: false,
|
|
163
|
+
showBoutDirectorAssignment: false
|
|
164
|
+
});
|
|
162
165
|
|
|
163
166
|
expect(wrapper.findComponent(BracketDirectorAssignmentPanel).exists()).toBe(false);
|
|
164
167
|
expect(wrapper.findComponent(Tableau).props('plannedDirectingStations')).toEqual([]);
|
|
165
168
|
});
|
|
166
169
|
});
|
|
170
|
+
|
|
171
|
+
describe('Bracket assignment defaults', () => {
|
|
172
|
+
it('shows assignment actions and the director panel without opt-in props', () => {
|
|
173
|
+
const wrapper = mountBracket();
|
|
174
|
+
expect(wrapper.findComponent(Tableau).props('showBoutDirectorAssignment')).toBe(true);
|
|
175
|
+
expect(wrapper.findComponent(BracketDirectorAssignmentPanel).exists()).toBe(true);
|
|
176
|
+
wrapper.unmount();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('forwards removal of a right-column director without changing authoritative bout fields', async () => {
|
|
180
|
+
const station = { RingId: 1, RingName: 'Ring 1', Director: { PersonId: 99, DisplayName: 'Dave Smith' } };
|
|
181
|
+
const bout = createBout({ Status: 'Active', RefereeId: 99, RefName: 'Dave Smith' });
|
|
182
|
+
const wrapper = mountBracket([bout], { plannedDirectingStations: [station] });
|
|
183
|
+
wrapper.findComponent(BracketDirectorAssignmentPanel).vm.$emit('request:remove-planned-director', station);
|
|
184
|
+
expect(wrapper.emitted('request:remove-planned-director')).toEqual([[station]]);
|
|
185
|
+
expect(wrapper.emitted('update:bout')).toBeUndefined();
|
|
186
|
+
expect(wrapper.vm.boutsData).toEqual([bout]);
|
|
187
|
+
expect(wrapper.props('plannedDirectingStations')).toEqual([station]);
|
|
188
|
+
await wrapper.setProps({ plannedDirectingStations: [] });
|
|
189
|
+
expect(wrapper.findComponent(BracketDirectorAssignmentPanel).props('stations')).toEqual([]);
|
|
190
|
+
wrapper.unmount();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('opens the staff-fed modal and forwards detached roster save intent without changing bout or station props', async () => {
|
|
194
|
+
const selected = {
|
|
195
|
+
RingId: 1,
|
|
196
|
+
RingName: 'Ring 1',
|
|
197
|
+
Director: { PersonId: 99, DisplayName: 'Dave Smith' },
|
|
198
|
+
Color: '#2563eb'
|
|
199
|
+
};
|
|
200
|
+
const wrapper = mountBracket(undefined, {
|
|
201
|
+
availableDirectors: [selected.Director],
|
|
202
|
+
rings: [{ RingId: 1, RingName: 'Ring 1' }],
|
|
203
|
+
plannedDirectingStations: [selected]
|
|
204
|
+
});
|
|
205
|
+
wrapper.findComponent(BracketDirectorAssignmentPanel).vm.$emit('request:add-planned-director');
|
|
206
|
+
await wrapper.vm.$nextTick();
|
|
207
|
+
const modal = wrapper.findComponent({ name: 'BracketDirectorsModal' });
|
|
208
|
+
expect(modal.props('show')).toBe(true);
|
|
209
|
+
expect(wrapper.emitted('request:add-planned-director')).toBeUndefined();
|
|
210
|
+
modal.vm.$emit('submit:stations', []);
|
|
211
|
+
await wrapper.vm.$nextTick();
|
|
212
|
+
expect(wrapper.emitted('update:planned-directing-stations')).toEqual([[[]]]);
|
|
213
|
+
expect(wrapper.props('plannedDirectingStations')).toEqual([selected]);
|
|
214
|
+
expect(wrapper.emitted('update:bout')).toBeUndefined();
|
|
215
|
+
expect(modal.props('show')).toBe(false);
|
|
216
|
+
wrapper.unmount();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<section>
|
|
3
|
-
<EditEventsTopMenu :currentTab="'Bracket'" :tabs="tabs(role,
|
|
3
|
+
<EditEventsTopMenu :currentTab="'Bracket'" :tabs="tabs(role, isMobile)" @tabMenuClick="handleTabMenuClick" />
|
|
4
4
|
<ToggleHeader
|
|
5
5
|
:currentSelection="viewName"
|
|
6
6
|
:key="viewName"
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
@update:selection="handleViewChange"
|
|
12
12
|
/>
|
|
13
13
|
|
|
14
|
+
<ServerConnected
|
|
15
|
+
class="mb-2 md:hidden"
|
|
16
|
+
:connectedToServer="connectedToServer"
|
|
17
|
+
:statusText="connectedToServer ? 'Connected' : 'Disconnected'"
|
|
18
|
+
/>
|
|
19
|
+
|
|
14
20
|
<div class="flex flex-col gap-4 xl:flex-row">
|
|
15
21
|
<div class="min-w-0 flex-1">
|
|
16
22
|
<Tableau
|
|
@@ -22,6 +28,8 @@
|
|
|
22
28
|
:plannedDirectingStations="plannedDirectingStations"
|
|
23
29
|
:plannedBoutAssignments="plannedBoutAssignments"
|
|
24
30
|
:viewerPersonId="viewerPersonId"
|
|
31
|
+
:showBoutDirectorAssignment="canShowBoutDirectorAssignment"
|
|
32
|
+
@request:bout-director="handleBoutDirectorRequest"
|
|
25
33
|
@action:editBout="editBout"
|
|
26
34
|
@action:directingBout="directBout"
|
|
27
35
|
/>
|
|
@@ -32,13 +40,16 @@
|
|
|
32
40
|
class="order-first flex-none xl:order-last"
|
|
33
41
|
:stations="plannedDirectingStations"
|
|
34
42
|
:showAddCard="showAddPlannedDirectorCard"
|
|
35
|
-
|
|
43
|
+
:canManageDirectors="canManagePlannedDirectors"
|
|
44
|
+
@request:manage-planned-directors="handleManagePlannedDirectors"
|
|
45
|
+
@request:add-planned-director="handleAddPlannedDirector"
|
|
46
|
+
@request:remove-planned-director="$emit('request:remove-planned-director', $event)"
|
|
36
47
|
/>
|
|
37
48
|
</div>
|
|
38
49
|
|
|
39
50
|
<div v-if="bouts.length < 1" class="w-full flex justify-center items-center">
|
|
40
51
|
<div class="text-center mb-10">
|
|
41
|
-
<img alt="Small desert scene with wind blowing." class="w-96 mx-auto" :src="emptyDesertIcon" />
|
|
52
|
+
<img alt="Small desert scene with wind blowing." class="hidden md:block w-96 mx-auto" :src="emptyDesertIcon" />
|
|
42
53
|
<BaseText text="Nothing to Show Yet!" size="lg" color="quinary" weight="bold" class="text-center" />
|
|
43
54
|
<BaseText
|
|
44
55
|
text="Check Back when this event has progress to Direct Elimination"
|
|
@@ -47,6 +58,7 @@
|
|
|
47
58
|
weight="normal"
|
|
48
59
|
/>
|
|
49
60
|
<BaseText
|
|
61
|
+
class="hidden md:block"
|
|
50
62
|
text="The Generate bracket button will appear on the bottom of the pools screen"
|
|
51
63
|
size="sm"
|
|
52
64
|
color="quinary"
|
|
@@ -55,6 +67,15 @@
|
|
|
55
67
|
</div>
|
|
56
68
|
</div>
|
|
57
69
|
|
|
70
|
+
<BracketDirectorsModal
|
|
71
|
+
v-if="canManagePlannedDirectors"
|
|
72
|
+
v-model:show="showPlannedDirectorsModal"
|
|
73
|
+
:availableDirectors="availableDirectors"
|
|
74
|
+
:rings="rings"
|
|
75
|
+
:stations="plannedDirectingStations"
|
|
76
|
+
@submit:stations="handlePlannedDirectorsSubmit"
|
|
77
|
+
/>
|
|
78
|
+
|
|
58
79
|
<DirectorModal
|
|
59
80
|
:bout="selectedBout"
|
|
60
81
|
:eventRules="eventRules"
|
|
@@ -84,13 +105,17 @@
|
|
|
84
105
|
<script>
|
|
85
106
|
import EditEventsTopMenu from '../../Menus/EditEventsTopMenu/EditEventsTopMenu.vue';
|
|
86
107
|
import ToggleHeader from '../../../Organisms/Headers/ToggleHeader/ToggleHeader.vue';
|
|
108
|
+
import ServerConnected from '../../../Molecules/Indicators/ServerConnected/ServerConnected.vue';
|
|
87
109
|
import BaseText from '../../../Atoms/Text/BaseText.vue';
|
|
88
110
|
import DirectorModal from '../../../Molecules/Modals/DirectorModal/DirectorModal.vue';
|
|
111
|
+
import BracketDirectorsModal from '../../../Molecules/Modals/BracketDirectorsModal/BracketDirectorsModal.vue';
|
|
112
|
+
import { cloneDirectorData } from '../../../Util/bracketDirectors.js';
|
|
89
113
|
import EditBoutModal from '../../../Molecules/Modals/EditBoutModal/EditBoutModal.vue';
|
|
90
114
|
import Tableau from '../../../Organisms/Containers/Tableau/Tableau.vue';
|
|
91
115
|
import BracketDirectorAssignmentPanel from '../../../Organisms/Containers/Tableau/components/BracketDirectorAssignmentPanel.vue';
|
|
92
116
|
import emptyDesertIcon from '../../../../assets/empty_desert_icon.png';
|
|
93
117
|
import { tabs } from '../../../Util/tabs.js';
|
|
118
|
+
import { canAssignBoutDirector } from '../../../Util/boutDirectorAssignment.js';
|
|
94
119
|
|
|
95
120
|
const isByeFencer = person => {
|
|
96
121
|
if (!person?.PersonId || Number(person.PersonId) === 0) return true;
|
|
@@ -110,7 +135,10 @@ export default {
|
|
|
110
135
|
'penalty:remove',
|
|
111
136
|
'penalty:update',
|
|
112
137
|
'request:add-planned-director',
|
|
138
|
+
'request:remove-planned-director',
|
|
139
|
+
'update:planned-directing-stations',
|
|
113
140
|
'request:bout-active',
|
|
141
|
+
'request:bout-director',
|
|
114
142
|
'submit:bout',
|
|
115
143
|
'tab:menu-click',
|
|
116
144
|
'update:bout',
|
|
@@ -121,11 +149,16 @@ export default {
|
|
|
121
149
|
EditBoutModal,
|
|
122
150
|
DirectorModal,
|
|
123
151
|
BracketDirectorAssignmentPanel,
|
|
152
|
+
BracketDirectorsModal,
|
|
124
153
|
BaseText,
|
|
125
154
|
ToggleHeader,
|
|
155
|
+
ServerConnected,
|
|
126
156
|
EditEventsTopMenu
|
|
127
157
|
},
|
|
128
158
|
props: {
|
|
159
|
+
availableDirectors: { type: Array, default: undefined },
|
|
160
|
+
rings: { type: Array, default: undefined },
|
|
161
|
+
showBoutDirectorAssignment: { type: Boolean, default: true },
|
|
129
162
|
bouts: {
|
|
130
163
|
type: Array,
|
|
131
164
|
required: true
|
|
@@ -164,7 +197,7 @@ export default {
|
|
|
164
197
|
},
|
|
165
198
|
showPlannedDirectorAssignments: {
|
|
166
199
|
type: Boolean,
|
|
167
|
-
default:
|
|
200
|
+
default: true
|
|
168
201
|
},
|
|
169
202
|
showAddPlannedDirectorCard: {
|
|
170
203
|
type: Boolean,
|
|
@@ -175,17 +208,30 @@ export default {
|
|
|
175
208
|
return {
|
|
176
209
|
emptyDesertIcon,
|
|
177
210
|
showDirectorModal: false,
|
|
211
|
+
showPlannedDirectorsModal: false,
|
|
178
212
|
showEditBoutModal: false,
|
|
179
213
|
selectedBout: {},
|
|
180
214
|
tabs,
|
|
181
215
|
viewName: 'Tableau',
|
|
182
216
|
boutsData: this.cloneBouts(this.bouts),
|
|
183
|
-
|
|
217
|
+
windowWidth: typeof window === 'undefined' ? 1024 : window.innerWidth
|
|
184
218
|
};
|
|
185
219
|
},
|
|
186
220
|
computed: {
|
|
221
|
+
canManagePlannedDirectors() {
|
|
222
|
+
return !this.isMobile && Array.isArray(this.availableDirectors) && Array.isArray(this.rings);
|
|
223
|
+
},
|
|
224
|
+
isMobile() {
|
|
225
|
+
return this.windowWidth < 768;
|
|
226
|
+
},
|
|
227
|
+
isListView() {
|
|
228
|
+
return this.isMobile || this.viewName === 'List View';
|
|
229
|
+
},
|
|
230
|
+
canShowBoutDirectorAssignment() {
|
|
231
|
+
return !this.isMobile && this.showBoutDirectorAssignment;
|
|
232
|
+
},
|
|
187
233
|
showPlannedAssignmentPanel() {
|
|
188
|
-
return this.showPlannedDirectorAssignments || this.plannedDirectingStations.length > 0;
|
|
234
|
+
return !this.isMobile && (this.showPlannedDirectorAssignments || this.plannedDirectingStations.length > 0);
|
|
189
235
|
},
|
|
190
236
|
isCountingBackwardsMaxScore() {
|
|
191
237
|
// 1) see if PoolScoreDirection exists and is explicitly "false"
|
|
@@ -213,6 +259,9 @@ export default {
|
|
|
213
259
|
}
|
|
214
260
|
},
|
|
215
261
|
watch: {
|
|
262
|
+
isMobile(value) {
|
|
263
|
+
if (value) this.showPlannedDirectorsModal = false;
|
|
264
|
+
},
|
|
216
265
|
bouts: {
|
|
217
266
|
handler(newBouts) {
|
|
218
267
|
this.boutsData = this.cloneBouts(newBouts);
|
|
@@ -230,6 +279,27 @@ export default {
|
|
|
230
279
|
window.removeEventListener('resize', this.updateViewBasedOnScreenSize);
|
|
231
280
|
},
|
|
232
281
|
methods: {
|
|
282
|
+
handleAddPlannedDirector() {
|
|
283
|
+
if (this.canManagePlannedDirectors) {
|
|
284
|
+
this.handleManagePlannedDirectors();
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
this.$emit('request:add-planned-director');
|
|
288
|
+
},
|
|
289
|
+
handleManagePlannedDirectors() {
|
|
290
|
+
if (!this.canManagePlannedDirectors) return;
|
|
291
|
+
this.showPlannedDirectorsModal = true;
|
|
292
|
+
},
|
|
293
|
+
handlePlannedDirectorsSubmit(stations) {
|
|
294
|
+
this.$emit('update:planned-directing-stations', cloneDirectorData(stations));
|
|
295
|
+
this.showPlannedDirectorsModal = false;
|
|
296
|
+
},
|
|
297
|
+
handleBoutDirectorRequest(bout) {
|
|
298
|
+
if (!this.canShowBoutDirectorAssignment) return;
|
|
299
|
+
const currentBout = this.boutsData.find(item => String(item.BoutId) === String(bout?.BoutId));
|
|
300
|
+
if (!canAssignBoutDirector(currentBout)) return;
|
|
301
|
+
this.$emit('request:bout-director', JSON.parse(JSON.stringify(currentBout)));
|
|
302
|
+
},
|
|
233
303
|
handleCloseModal() {
|
|
234
304
|
const closedDirectingBout = this.showDirectorModal && this.selectedBout?.BoutId ? { ...this.selectedBout } : null;
|
|
235
305
|
this.showDirectorModal = false;
|
|
@@ -242,7 +312,6 @@ export default {
|
|
|
242
312
|
},
|
|
243
313
|
handleViewChange(value) {
|
|
244
314
|
this.viewName = value;
|
|
245
|
-
this.isListView = value === 'List View';
|
|
246
315
|
},
|
|
247
316
|
handleUpdateBout(bout) {
|
|
248
317
|
if (!bout?.BoutId) return;
|
|
@@ -279,7 +348,7 @@ export default {
|
|
|
279
348
|
this.selectedBout = updatedBout;
|
|
280
349
|
},
|
|
281
350
|
updateViewBasedOnScreenSize() {
|
|
282
|
-
this.
|
|
351
|
+
this.windowWidth = window.innerWidth;
|
|
283
352
|
},
|
|
284
353
|
handleUpdatePenalty(penalty) {
|
|
285
354
|
this.$emit('penalty:update', penalty);
|