@dcrackel/hematournamentui 1.0.699 → 1.0.701

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 (67) hide show
  1. package/AGENTS.md +3 -0
  2. package/dist/HemaTournamentUI-lib.es.js +10512 -10219
  3. package/dist/HemaTournamentUI-lib.umd.js +27 -27
  4. package/dist/hematournamentui-tailwind.css +14 -0
  5. package/dist/hematournamentui.css +1 -1
  6. package/package.json +92 -92
  7. package/src/stories/Molecules/Boxes/BoutBoxes/TimerBox/TimerBox.vue +1 -1
  8. package/src/stories/Molecules/Buttons/BaseButton/BaseButton.vue +1 -1
  9. package/src/stories/Molecules/Modals/DirectorModal/DirectorModal.vue +2 -2
  10. package/src/stories/Organisms/Cards/BoutCard/Variants/BoutCardActive/BoutCardActive.vue +25 -22
  11. package/src/stories/Organisms/Cards/BoutCard/Variants/BoutCardInactive/BoutCardInactive.vue +31 -29
  12. package/src/stories/Organisms/Cards/BoutCard/Variants/BoutCardWaiting/BoutCardWaiting.vue +2 -4
  13. package/src/stories/Organisms/Cards/KioskCard/KioskCard.vue +31 -31
  14. package/src/stories/Organisms/Cards/PenaltyCard/PenaltyCard.stories.js +6 -6
  15. package/src/stories/Organisms/Cards/PenaltyCard/PenaltyCard.vue +64 -53
  16. package/src/stories/Organisms/Cards/PenaltyFencerCard/PenaltyFencerCard.stories.js +6 -7
  17. package/src/stories/Organisms/Cards/PenaltyFencerCard/PenaltyFencerCard.vue +18 -10
  18. package/src/stories/Organisms/Cards/StaffCard/StaffCard.vue +4 -4
  19. package/src/stories/Organisms/ComplexInputs/DatePicker/DatePicker.vue +64 -45
  20. package/src/stories/Organisms/Containers/Pool/Pool.vue +1 -1
  21. package/src/stories/Organisms/Containers/PoolResults/PoolResultsTable.vue +35 -20
  22. package/src/stories/Templates/Assignment/Assignment.stories.js +17 -15
  23. package/src/stories/Templates/Assignment/Assignment.vue +71 -40
  24. package/src/stories/Templates/ClubManagement/ClubBasic/ClubBasic.stories.js +49 -30
  25. package/src/stories/Templates/ClubManagement/ClubBasic/ClubBasic.vue +29 -28
  26. package/src/stories/Templates/ClubManagement/{ClubMangement.stories.js → ClubManagement.stories.js} +74 -59
  27. package/src/stories/Templates/ClubManagement/ClubManagement.vue +104 -92
  28. package/src/stories/Templates/EventManagement/Bracket/Bracket.vue +92 -97
  29. package/src/stories/Templates/EventManagement/EditEventInfo/EditEventInfo.stories.js +37 -33
  30. package/src/stories/Templates/EventManagement/EditEventInfo/EditEventInfo.vue +11 -14
  31. package/src/stories/Templates/EventManagement/EventAttendance/EventAttendance.vue +34 -37
  32. package/src/stories/Templates/EventManagement/EventFinalResults/EventFinalResults.stories.js +11 -10
  33. package/src/stories/Templates/EventManagement/EventFinalResults/EventFinalResults.vue +8 -8
  34. package/src/stories/Templates/EventManagement/KioskDisplay/KioskDisplay.stories.js +13 -16
  35. package/src/stories/Templates/EventManagement/KioskDisplay/KioskDisplay.vue +15 -19
  36. package/src/stories/Templates/EventManagement/Penalties/PenaltyReport.stories.js +25 -24
  37. package/src/stories/Templates/EventManagement/Penalties/PenaltyReport.vue +28 -34
  38. package/src/stories/Templates/EventManagement/PoolLive/PoolLive.stories.js +54 -19
  39. package/src/stories/Templates/EventManagement/PoolLive/PoolLive.vue +75 -68
  40. package/src/stories/Templates/EventManagement/PoolManagement/PoolManagement.stories.js +55 -45
  41. package/src/stories/Templates/EventManagement/PoolManagement/PoolManagement.vue +47 -55
  42. package/src/stories/Templates/EventManagement/PoolResults/PoolResults.stories.js +56 -55
  43. package/src/stories/Templates/EventManagement/PoolResults/PoolResults.vue +71 -73
  44. package/src/stories/Templates/EventManagement/StaffList/StaffList.stories.js +18 -16
  45. package/src/stories/Templates/EventManagement/StaffList/StaffList.vue +9 -6
  46. package/src/stories/Templates/Menus/Admin/AdminLeftMenu.stories.js +22 -19
  47. package/src/stories/Templates/Menus/Admin/AdminLeftMenu.vue +44 -36
  48. package/src/stories/Templates/Menus/EditEventsTopMenu/EditEventsTopMenu.stories.js +30 -23
  49. package/src/stories/Templates/Menus/EditEventsTopMenu/EditEventsTopMenu.vue +55 -58
  50. package/src/stories/Templates/PersonManagement/Admin/Administration/Administration.stories.js +67 -0
  51. package/src/stories/Templates/PersonManagement/Admin/{Administration.vue → Administration/Administration.vue} +94 -87
  52. package/src/stories/Templates/PersonManagement/Admin/FencerAdmin/FencerAdmin.stories.js +71 -0
  53. package/src/stories/Templates/PersonManagement/Admin/{FencerAdmin.vue → FencerAdmin/FencerAdmin.vue} +90 -77
  54. package/src/stories/Templates/PersonManagement/Admin/MergeAccounts/MergeAccounts.stories.js +86 -0
  55. package/src/stories/Templates/PersonManagement/Admin/{MergeAccounts.vue → MergeAccounts/MergeAccounts.vue} +258 -242
  56. package/src/stories/Templates/PersonManagement/Attendance/Attendance.vue +28 -28
  57. package/src/stories/Templates/PersonManagement/PersonManagement.vue +1 -1
  58. package/src/stories/Templates/TournamentManagement/ListEvents/ListEvents.stories.js +45 -28
  59. package/src/stories/Templates/TournamentManagement/ListEvents/ListEvents.vue +22 -16
  60. package/src/stories/Templates/TournamentManagement/{TournamentMangement.stories.js → TournamentManagement.stories.js} +68 -39
  61. package/src/stories/Templates/TournamentManagement/TournamentManagement.vue +199 -153
  62. package/src/stories/Templates/TournamentManagement/TournamentPageOne/TournamentPageOne.stories.js +113 -0
  63. package/src/stories/Templates/TournamentManagement/TournamentPageOne/TournamentPageOne.vue +123 -106
  64. package/src/stories/Templates/TournamentManagement/TournamentPageTwo/TournamentPageTwo.stories.js +76 -31
  65. package/src/stories/Templates/TournamentManagement/TournamentPageTwo/{TouranmentPageTwo.vue → TournamentPageTwo.vue} +63 -44
  66. package/src/stories/Templates/PersonManagement/Admin/FencerAdmin.stories.js +0 -48
  67. package/src/stories/Templates/TournamentManagement/TournamentPageOne/TouranmentPageOne.stories.js +0 -63
@@ -1,28 +1,45 @@
1
- import EditEvents from './ListEvents.vue';
2
- import eventMockData from '../../../../mocks/eventMock.js';
3
-
4
- export default {
5
- title: 'Templates/TournamentManagement/ListEvents',
6
- component: EditEvents,
7
- tags: ['autodocs'],
8
- args: {
9
- events: eventMockData,
10
- },
11
- argTypes: {
12
- }
13
- };
14
-
15
- export const Default = {
16
- args: {
17
- tournamentId: 8,
18
- events: eventMockData
19
- }
20
- };
21
-
22
-
23
- export const NoEvents = {
24
- args: {
25
- tournamentId: 8,
26
- events: []
27
- }
28
- };
1
+ import ListEvents from './ListEvents.vue';
2
+ import eventMockData from '../../../../mocks/eventMock.js';
3
+
4
+ export default {
5
+ title: 'Templates/TournamentManagement/ListEvents',
6
+ component: ListEvents,
7
+ tags: ['autodocs'],
8
+ args: {
9
+ tournamentId: 8,
10
+ events: eventMockData,
11
+ },
12
+ argTypes: {
13
+ tournamentId: { control: { type: 'number' } },
14
+ events: { control: { type: 'object' } },
15
+ 'tab:menu-click': { action: 'tab:menu-click' },
16
+ manageEvent: { action: 'manageEvent' },
17
+ editEvent: { action: 'editEvent' },
18
+ addEvent: { action: 'addEvent' },
19
+ 'delete:Event': { action: 'delete:Event' }
20
+ }
21
+ };
22
+
23
+ export const Default = {
24
+ args: {
25
+ tournamentId: 8,
26
+ events: eventMockData
27
+ }
28
+ };
29
+
30
+ export const NoEvents = {
31
+ args: {
32
+ tournamentId: 8,
33
+ events: []
34
+ }
35
+ };
36
+
37
+ export const CompletedEvents = {
38
+ args: {
39
+ tournamentId: 8,
40
+ events: eventMockData.map((event) => ({
41
+ ...event,
42
+ Status: 'completed'
43
+ }))
44
+ }
45
+ };
@@ -1,9 +1,9 @@
1
1
  <template>
2
2
  <section class="mx-2 md:mx-4">
3
3
  <EditEventsTopMenu :currentTab="'Events'" :tabs="tabs" @tabMenuClick="handleTabMenuClick"/>
4
- <div class="w-full flex flex-row justify-center">
5
- <section class="w-full">
6
- <div class="w-full flex flex-col justify-center items-center mb-6" style="text-align: center">
4
+ <div class="w-full flex flex-row justify-center">
5
+ <section class="w-full">
6
+ <div class="w-full flex flex-col justify-center items-center mb-6 text-center">
7
7
  <div v-if="events.length === 0">
8
8
  <img alt="Small desert scene with wind blowing." class="w-96" :src="emptyDesertIcon" />
9
9
  <BaseText :color="'primaryHighlight'" size=" " :text="'0 events added yet.'"
@@ -12,7 +12,7 @@
12
12
  :weight="'normal'" data-testid="text-num-events" class="text-sm md:text-md" />
13
13
  </div>
14
14
 
15
- <section v-for="event in events" class="w-full">
15
+ <section v-for="event in events" :key="event.EventId" class="w-full">
16
16
  <EventCard :event="event"
17
17
  @edit="handleEdit(event.EventId)"
18
18
  @manage="handleManageEvent(event.EventId)"
@@ -39,24 +39,30 @@ import emptyDesertIcon from '../../../../assets/empty_desert_icon.png';
39
39
  import EditEventsTopMenu from "../../Menus/EditEventsTopMenu/EditEventsTopMenu.vue";
40
40
  import {tournamentTabs} from "../../../Util/tabs.js";
41
41
 
42
- export default {
43
- components: {
42
+ export default {
43
+ name: 'ListEvents',
44
+ components: {
44
45
  EditEventsTopMenu,
45
46
  EventCard,
46
47
  BaseText,
47
48
  BaseButton
48
- },
49
- props: {
50
- tournamentId: Number,
51
- events: Array,
52
- },
49
+ },
50
+ props: {
51
+ tournamentId: {
52
+ type: Number,
53
+ required: true
54
+ },
55
+ events: {
56
+ type: Array,
57
+ default: () => []
58
+ },
59
+ },
53
60
  emits: ['tab:menu-click', 'manageEvent', 'editEvent', 'addEvent', 'delete:Event'],
54
61
  data() {
55
62
  return {
56
- emptyDesertIcon,
57
- currentTab: 'Events',
58
- tabs: tournamentTabs()
59
- };
63
+ emptyDesertIcon,
64
+ tabs: tournamentTabs()
65
+ };
60
66
  },
61
67
  methods: {
62
68
  handleAddEvent() {
@@ -76,4 +82,4 @@ export default {
76
82
  }
77
83
  }
78
84
  }
79
- </script>
85
+ </script>
@@ -1,40 +1,60 @@
1
1
  import TournamentManagement from "./TournamentManagement.vue";
2
2
  import mockLocation from "../../../mocks/locationMock.js";
3
- import mockPersons from "../../../mocks/personsMock.js";
4
- import mockTournaments from "../../../mocks/tournamentMock.js";
5
-
6
- export default {
7
- title: 'Templates/TournamentManagement',
8
- component: TournamentManagement,
9
- tags: ["autodocs"],
10
- args: {
11
- tournament: mockTournaments,
12
- locations: mockLocation,
13
- persons: mockPersons,
14
- uploadImageName: 'tournament-test',
15
- uploadServer: 'http://localhost:3000/api/upload/',
16
- imageServer: 'https://meyersquaredimages.com/uploads/',
17
- },
18
- argTypes: {
19
- tournament: {
20
- control: { type: "object" },
3
+ import mockPersons from "../../../mocks/personsMock.js";
4
+ import mockTournaments from "../../../mocks/tournamentMock.js";
5
+
6
+ const existingTournament = {
7
+ ...mockTournaments[0],
8
+ HostedOnM2: true,
9
+ ResultsEnabled: false,
10
+ Visibility: 'Open',
11
+ WaiverScope: 'None',
12
+ };
13
+
14
+ export default {
15
+ title: 'Templates/TournamentManagement',
16
+ component: TournamentManagement,
17
+ tags: ["autodocs"],
18
+ args: {
19
+ tournament: existingTournament,
20
+ locations: mockLocation,
21
+ persons: mockPersons,
22
+ uploadImageName: 'tournament-test',
23
+ uploadServer: 'http://localhost:3000/api/upload/',
24
+ imageServer: 'https://meyersquaredimages.com/uploads/',
25
+ showTab: 'Basic',
26
+ userLevel: 'Club',
27
+ submitButtonLabel: 'Save',
28
+ },
29
+ argTypes: {
30
+ tournament: {
31
+ control: { type: "object" },
21
32
  },
22
33
  locations: {
23
34
  control: { type: "object" },
24
35
  },
25
- persons: {
26
- control: { type: "object" },
27
- },
28
- },
29
- };
30
-
31
- export const Default = {
32
- args: {
33
- tournament: mockTournaments[0],
34
- locations: mockLocation,
35
- persons: mockPersons,
36
- },
37
- };
36
+ persons: {
37
+ control: { type: "object" },
38
+ },
39
+ showTab: {
40
+ control: { type: "text" },
41
+ },
42
+ userLevel: {
43
+ control: { type: "text" },
44
+ },
45
+ submitButtonLabel: {
46
+ control: { type: "text" },
47
+ },
48
+ },
49
+ };
50
+
51
+ export const Default = {
52
+ args: {
53
+ tournament: existingTournament,
54
+ locations: mockLocation,
55
+ persons: mockPersons,
56
+ },
57
+ };
38
58
 
39
59
  export const EmptyTournament = {
40
60
  args: {
@@ -44,11 +64,20 @@ export const EmptyTournament = {
44
64
  },
45
65
  };
46
66
 
47
- export const StartOnDetails = {
48
- args: {
49
- tournament: mockTournaments,
50
- locations: mockLocation,
51
- persons: mockPersons,
52
- showTab: "Hosting",
53
- },
54
- };
67
+ export const StartOnDetails = {
68
+ args: {
69
+ tournament: existingTournament,
70
+ locations: mockLocation,
71
+ persons: mockPersons,
72
+ showTab: "Hosting",
73
+ },
74
+ };
75
+
76
+ export const Saving = {
77
+ args: {
78
+ tournament: existingTournament,
79
+ locations: mockLocation,
80
+ persons: mockPersons,
81
+ submitButtonLabel: "Saving...",
82
+ },
83
+ };
@@ -11,10 +11,11 @@
11
11
  :uploadServer="uploadServer"
12
12
  :isNewTournament="isNewTournament"
13
13
  :userLevel="userLevel"
14
- @add:newAddress="handleAddNewAddress"
15
- @update:address="handleAddressUpdate"
16
- @update:image="handleNewImageUrl"
17
- @update:tournament="updateTournament"
14
+ @add:newAddress="handleAddNewAddress"
15
+ @add:newPerson="handleAddNewPerson"
16
+ @update:address="handleAddressUpdate"
17
+ @update:image="handleNewImageUrl"
18
+ @update:tournament="updateTournament"
18
19
  />
19
20
 
20
21
  <TournamentPageTwo v-if="currentTab === 'Hosting'"
@@ -30,43 +31,37 @@
30
31
  <BaseButton v-if="currentTab === 'Hosting'" class="w-1/2 ml-1 h-12" color="neutral" label="Back" size="sm"
31
32
  type="primary" @buttonClick="handleBack"/>
32
33
 
33
- <BaseButton v-if="currentTab === 'Basic'" class="w-1/2 mr-1 transition-all duration-300 ease-in-out h-12"
34
- color="neutral" label="Next" selected=selected size="sm" type="primary" @buttonClick="handleNext"/>
35
- <BaseButton v-if="currentTab === 'Hosting'" class="w-1/2 mr-1 transition-all duration-300 ease-in-out h-12"
36
- color="neutral" :label="saveButtonLabel" selected=selected size="sm" type="primary"
37
- @buttonClick="handleSubmit"/>
38
- </div>
39
-
40
- <div v-if="!isNewTournament" class="flex flex-row justify-center h-12 mt-4">
41
- <BaseButton class="w-1/2 mr-1 transition-all duration-300 ease-in-out h-12" color="neutral"
42
- :label="saveButtonLabel" selected=selected size="sm" type="primary" @buttonClick="handleSubmit"/>
43
- </div>
34
+ <BaseButton v-if="currentTab === 'Basic'" class="w-1/2 mr-1 transition-all duration-300 ease-in-out h-12"
35
+ color="neutral" label="Next" :selected="true" size="sm" type="primary" @buttonClick="handleNext"/>
36
+ <BaseButton v-if="currentTab === 'Hosting'" class="w-1/2 mr-1 transition-all duration-300 ease-in-out h-12"
37
+ color="neutral" :label="submitButtonLabel" :selected="true" size="sm" type="primary"
38
+ @buttonClick="handleSubmit"/>
39
+ </div>
40
+
41
+ <div v-if="!isNewTournament" class="flex flex-row justify-center h-12 mt-4">
42
+ <BaseButton class="w-1/2 mr-1 transition-all duration-300 ease-in-out h-12" color="neutral"
43
+ :label="submitButtonLabel" :selected="true" size="sm" type="primary" @buttonClick="handleSubmit"/>
44
+ </div>
44
45
  </div>
45
46
  </template>
46
47
 
47
48
  <script>
48
- import TournamentPageOne from "./TournamentPageOne/TournamentPageOne.vue";
49
- import BaseText from "../../Atoms/Text/BaseText.vue";
50
- import ImageCropper from "../../Organisms/ComplexInputs/ImageCropper/ImageCropper.vue";
51
- import BaseButton from "../../Molecules/Buttons/BaseButton/BaseButton.vue";
52
- import EditEventsTopMenu from "../Menus/EditEventsTopMenu/EditEventsTopMenu.vue";
53
- import {tournamentTabs} from "../../Util/tabs.js";
54
- import TournamentPageTwo from "./TournamentPageTwo/TouranmentPageTwo.vue";
55
- import {validateField} from "../../Util/Validations/TournamentFieldsValidations.js";
56
- import BaseModal from "../../Molecules/Modals/BaseModal/BaseModal.vue";
57
-
58
- export default {
59
- title: 'TournamentManagement',
60
- components: {
61
- TournamentPageTwo,
62
- EditEventsTopMenu,
63
- BaseButton,
64
- ImageCropper,
65
- BaseText,
66
- TournamentPageOne,
67
- BaseModal
68
- },
69
- emits: ['submit:tournament', 'cancel', 'add:newAddress', 'update:address', 'update:image', 'tab:menu-click'],
49
+ import TournamentPageOne from "./TournamentPageOne/TournamentPageOne.vue";
50
+ import BaseButton from "../../Molecules/Buttons/BaseButton/BaseButton.vue";
51
+ import EditEventsTopMenu from "../Menus/EditEventsTopMenu/EditEventsTopMenu.vue";
52
+ import {tournamentTabs} from "../../Util/tabs.js";
53
+ import TournamentPageTwo from "./TournamentPageTwo/TournamentPageTwo.vue";
54
+ import {validateField} from "../../Util/Validations/TournamentFieldsValidations.js";
55
+
56
+ export default {
57
+ title: 'TournamentManagement',
58
+ components: {
59
+ TournamentPageTwo,
60
+ EditEventsTopMenu,
61
+ BaseButton,
62
+ TournamentPageOne,
63
+ },
64
+ emits: ['submit:tournament', 'cancel', 'add:newAddress', 'add:newPerson', 'update:address', 'update:image', 'tab:menu-click'],
70
65
  props: {
71
66
  tournament: {
72
67
  type: Object,
@@ -97,34 +92,42 @@ export default {
97
92
  type: String,
98
93
  default: 'Basic'
99
94
  },
100
- userLevel: {
101
- type: String,
102
- default: 'Club'
103
- }
104
- },
105
- data() {
106
- return {
107
- currentTab: this.showTab,
108
- localTournament: this.tournament,
109
- isNewTournament: true,
110
- saveButtonLabel: 'Save',
111
- validation: {
112
- Name: {invalid: false, message: ""},
113
- Address: {invalid: false, message: ""},
114
- StartDate: {invalid: false, message: ""},
115
- TotalDays: {invalid: false, message: ""},
116
- RegistrationCutOff: {invalid: false, message: ""},
117
- Description: {invalid: false, message: ""},
118
- WaiverScope: "None",
119
- },
120
- };
121
- },
122
- watch: {
123
- 'localTournament.StartDate': 'setEndDate',
124
- 'localTournament.TotalDays': 'setEndDate',
125
- },
126
- mounted() {
127
- this.checkIfNewTournament();
95
+ userLevel: {
96
+ type: String,
97
+ default: 'Club'
98
+ },
99
+ submitButtonLabel: {
100
+ type: String,
101
+ default: 'Save'
102
+ }
103
+ },
104
+ data() {
105
+ return {
106
+ currentTab: this.showTab,
107
+ localTournament: this.createNewTournamentDraft(),
108
+ isNewTournament: true,
109
+ validation: {
110
+ Name: {invalid: false, message: ""},
111
+ Address: {invalid: false, message: ""},
112
+ StartDate: {invalid: false, message: ""},
113
+ TotalDays: {invalid: false, message: ""},
114
+ RegistrationCutOff: {invalid: false, message: ""},
115
+ Description: {invalid: false, message: ""},
116
+ },
117
+ };
118
+ },
119
+ watch: {
120
+ tournament: {
121
+ handler: 'initializeTournamentDraft',
122
+ },
123
+ showTab(tab) {
124
+ this.currentTab = tab;
125
+ },
126
+ 'localTournament.StartDate': 'setEndDate',
127
+ 'localTournament.TotalDays': 'setEndDate',
128
+ },
129
+ mounted() {
130
+ this.initializeTournamentDraft();
128
131
  },
129
132
  computed: {
130
133
  filteredTabs() {
@@ -137,60 +140,81 @@ export default {
137
140
  },
138
141
  },
139
142
  methods: {
140
- tournamentTabs,
141
- handleTab(tab) {
142
- this.saveButtonLabel = 'Save';
143
- this.currentTab = tab;
144
- this.$emit('tab:menu-click', tab);
145
- },
146
- checkIfNewTournament() {
147
- if (!this.tournament || Object.keys(this.tournament).length === 0 || !this.tournament.Name) {
148
- this.isNewTournament = true;
149
- this.localTournament = {
150
- TournamentId: 0,
151
- Name: "",
152
- Address: "",
153
- TotalDays: 1,
154
- StartDate: new Date().toISOString().slice(0, 10),
155
- RegistrationCutOff: new Date().toISOString().slice(0, 10),
156
- Description: "",
157
- HostedOnM2: false,
158
- Visibility: "Open"
159
- };
160
- return;
161
- }
162
-
163
- this.isNewTournament = false;
164
-
165
- const startDate = new Date(this.tournament.StartDate);
166
- const endDate = new Date(this.tournament.EndDate);
167
- const TotalDays = (!isNaN(startDate.getTime()) && !isNaN(endDate.getTime()))
168
- ? Math.max(1, (endDate - startDate) / (1000 * 60 * 60 * 24) + 1)
169
- : 1;
170
-
171
- this.localTournament = {...this.tournament, TotalDays, WaiverScope: this.tournament.WaiverScope ?? "None",};
172
- console.log(this.localTournament)
173
- this.setEndDate();
174
- },
175
- handleAddNewAddress(newAddress) {
176
- this.localTournament.AddressId = 0;
177
- this.localTournament.Address = newAddress;
178
-
179
- this.$emit('add:newAddress', newAddress);
180
- },
181
- handleAddressUpdate(updatedAddress) {
182
- if (updatedAddress) {
183
- this.localTournament.AddressId = updatedAddress.AddressId
184
- this.localTournament.Address = updatedAddress;
185
- this.$emit('update:address', updatedAddress);
186
- this.validation.Address = validateField('Address', updatedAddress);
187
- }
188
-
189
- if (!updatedAddress) {
190
- this.localTournament.AddressId = 0;
191
- this.localTournament.Address = '';
192
- }
193
- },
143
+ tournamentTabs,
144
+ handleTab(tab) {
145
+ this.currentTab = tab;
146
+ this.$emit('tab:menu-click', tab);
147
+ },
148
+ initializeTournamentDraft() {
149
+ if (!this.tournament || Object.keys(this.tournament).length === 0 || !this.tournament.Name) {
150
+ this.isNewTournament = true;
151
+ this.localTournament = this.createNewTournamentDraft();
152
+ return;
153
+ }
154
+
155
+ this.isNewTournament = false;
156
+ this.localTournament = this.createExistingTournamentDraft(this.tournament);
157
+ this.setEndDate();
158
+ },
159
+ createNewTournamentDraft() {
160
+ const today = new Date().toISOString().slice(0, 10);
161
+
162
+ return {
163
+ TournamentId: 0,
164
+ Name: "",
165
+ Address: "",
166
+ TotalDays: 1,
167
+ StartDate: today,
168
+ RegistrationCutOff: today,
169
+ Description: "",
170
+ HostedOnM2: false,
171
+ ResultsEnabled: false,
172
+ Visibility: "Open",
173
+ WaiverScope: "None",
174
+ };
175
+ },
176
+ createExistingTournamentDraft(tournament) {
177
+ const tournamentDraft = this.cloneTournamentData(tournament);
178
+ const startDate = new Date(tournamentDraft.StartDate);
179
+ const endDate = new Date(tournamentDraft.EndDate);
180
+ const TotalDays = (!isNaN(startDate.getTime()) && !isNaN(endDate.getTime()))
181
+ ? Math.max(1, (endDate - startDate) / (1000 * 60 * 60 * 24) + 1)
182
+ : 1;
183
+
184
+ return {
185
+ ...tournamentDraft,
186
+ TotalDays,
187
+ StartDate: this.formatDateOnly(tournamentDraft.StartDate),
188
+ EndDate: this.formatDateOnly(tournamentDraft.EndDate),
189
+ RegistrationCutOff: this.formatDateOnly(tournamentDraft.RegistrationCutOff),
190
+ Visibility: tournamentDraft.Visibility ?? "Open",
191
+ WaiverScope: tournamentDraft.WaiverScope ?? "None",
192
+ ResultsEnabled: tournamentDraft.ResultsEnabled ?? false,
193
+ };
194
+ },
195
+ cloneTournamentData(tournament) {
196
+ return JSON.parse(JSON.stringify(tournament));
197
+ },
198
+ handleAddNewAddress(newAddress) {
199
+ this.updateTournament({ AddressId: 0, Address: newAddress });
200
+ this.$emit('add:newAddress', newAddress);
201
+ },
202
+ handleAddNewPerson(personName) {
203
+ this.$emit('add:newPerson', personName);
204
+ },
205
+ handleAddressUpdate(updatedAddress) {
206
+ if (updatedAddress) {
207
+ this.updateTournament({
208
+ AddressId: updatedAddress.AddressId,
209
+ Address: updatedAddress,
210
+ });
211
+ this.$emit('update:address', updatedAddress);
212
+ this.validation.Address = validateField('Address', updatedAddress);
213
+ return;
214
+ }
215
+
216
+ this.updateTournament({ AddressId: 0, Address: "" });
217
+ },
194
218
  validateAllFields() {
195
219
  const fieldsToValidate = ['Name', 'TotalDays', 'Address'];
196
220
  fieldsToValidate.forEach(field => {
@@ -198,32 +222,60 @@ export default {
198
222
  });
199
223
  return !Object.values(this.validation).some(field => field.invalid);
200
224
  },
201
- handleNewImageUrl(url) {
202
- this.tournament.imageLink = url;
203
- this.$emit('update:image', url);
204
- },
205
- updateTournament(updatedData) {
206
- this.localTournament = {...this.localTournament, ...updatedData};
207
- Object.keys(updatedData).forEach(field => {
208
- if (this.validation[field]) {
209
- this.validation[field] = validateField(field, updatedData[field]);
210
- }
211
- });
212
- },
213
- addDaysInclusiveYMD(startYmd, totalDays) {
214
- const [y, m, d] = startYmd.split('-').map(Number);
215
- const start = new Date(Date.UTC(y, m - 1, d));
225
+ handleNewImageUrl(imageUpdate) {
226
+ this.updateTournament(imageUpdate);
227
+ this.$emit('update:image', imageUpdate);
228
+ },
229
+ updateTournament(updatedData) {
230
+ const normalizedData = this.normalizeTournamentUpdate(updatedData);
231
+ this.localTournament = {...this.localTournament, ...normalizedData};
232
+ Object.keys(normalizedData).forEach(field => {
233
+ if (this.validation[field]) {
234
+ this.validation[field] = validateField(field, normalizedData[field]);
235
+ }
236
+ });
237
+ },
238
+ normalizeTournamentUpdate(updatedData) {
239
+ const normalizedData = {...updatedData};
240
+ const dateFields = ['StartDate', 'EndDate', 'RegistrationCutOff'];
241
+
242
+ dateFields.forEach(field => {
243
+ if (field in normalizedData) {
244
+ normalizedData[field] = this.formatDateOnly(normalizedData[field]);
245
+ }
246
+ });
247
+
248
+ return normalizedData;
249
+ },
250
+ formatDateOnly(dateValue) {
251
+ if (!dateValue) return "";
252
+ if (typeof dateValue === 'string') return dateValue.slice(0, 10);
253
+
254
+ const date = new Date(dateValue);
255
+ if (isNaN(date.getTime())) return "";
256
+
257
+ const year = date.getFullYear();
258
+ const month = String(date.getMonth() + 1).padStart(2, '0');
259
+ const day = String(date.getDate()).padStart(2, '0');
260
+ return `${year}-${month}-${day}`;
261
+ },
262
+ addDaysInclusiveYMD(startYmd, totalDays) {
263
+ const [y, m, d] = startYmd.split('-').map(Number);
264
+ const start = new Date(Date.UTC(y, m - 1, d));
216
265
  const end = new Date(start);
217
266
  end.setUTCDate(end.getUTCDate() + Math.max(1, Number(totalDays) || 1) - 1);
218
267
  return end.toISOString().slice(0, 10); // 'YYYY-MM-DD'
219
268
  },
220
- setEndDate() {
221
- if (!this.localTournament?.StartDate) return;
222
- const days = Math.max(1, Number(this.localTournament.TotalDays) || 1);
223
- this.localTournament.EndDate = this.addDaysInclusiveYMD(this.localTournament.StartDate, days);
224
- },
225
- handleCancel() {
226
- this.$emit('edit:cancel');
269
+ setEndDate() {
270
+ if (!this.localTournament?.StartDate) return;
271
+ const startDate = this.formatDateOnly(this.localTournament.StartDate);
272
+ if (!startDate) return;
273
+
274
+ const days = Math.max(1, Number(this.localTournament.TotalDays) || 1);
275
+ this.localTournament.EndDate = this.addDaysInclusiveYMD(startDate, days);
276
+ },
277
+ handleCancel() {
278
+ this.$emit('cancel');
227
279
  },
228
280
  transition(action) {
229
281
  const table = {
@@ -253,17 +305,11 @@ export default {
253
305
  handleBack() {
254
306
  this.transition('BACK');
255
307
  },
256
- handleSubmit() {
257
- console.log(this.tournament)
258
- if (this.validateAllFields()) {
259
- this.saveButtonLabel = 'Saving...';
260
- setTimeout(() => {
261
- this.saveButtonLabel = 'Saved!';
262
- }, 2000);
263
-
264
- this.$emit('submit:tournament', this.localTournament);
265
- }
266
- },
308
+ handleSubmit() {
309
+ if (this.validateAllFields()) {
310
+ this.$emit('submit:tournament', this.localTournament);
311
+ }
312
+ },
267
313
  },
268
314
  };
269
- </script>
315
+ </script>