@dcrackel/hematournamentui 1.0.688 → 1.0.691

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.
@@ -6,4 +6,4 @@
6
6
  * Released under the MIT license
7
7
  *
8
8
  * Date: 2024-04-21T07:43:02.731Z
9
- */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;touch-action:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.cropper-container img{backface-visibility:hidden;display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-wrap-box,.cropper-canvas,.cropper-drag-box,.cropper-crop-box,.cropper-modal{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-wrap-box,.cropper-canvas{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:#3399ffbf;overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:calc(100% / 3);left:0;top:calc(100% / 3);width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:calc(100% / 3);top:0;width:calc(100% / 3)}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:before,.cropper-center:after{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media(min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media(min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media(min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}[data-v-a1dce3ee] .ProseMirror>*+*{margin-top:.75em}[data-v-a1dce3ee] .ProseMirror ol{padding:0 1rem;list-style:decimal!important}[data-v-a1dce3ee] .ProseMirror ul{padding:0 1rem;list-style:disc!important}[data-v-c53fc36c]::-webkit-scrollbar{width:15px;height:15px}[data-v-c53fc36c]::-webkit-scrollbar-track{background:#f6fafd}[data-v-c53fc36c]::-webkit-scrollbar-thumb{background:#d5e4ee;border-radius:5px}[data-v-c53fc36c]::-webkit-scrollbar-thumb:hover{background:#c3cce0}.fade-in-down-enter-active[data-v-507c44cb]{animation:fadeInDown-507c44cb .3s ease-out}.fade-in-down-leave-active[data-v-507c44cb]{animation:fadeOutUp-507c44cb .3s ease-in;max-height:100px;overflow:hidden}.fade-in-down-leave-to[data-v-507c44cb]{opacity:0;transform:translateY(-10px);max-height:0;overflow:hidden}@keyframes fadeInDown-507c44cb{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeOutUp-507c44cb{0%{opacity:1;transform:translateY(0);max-height:100px}to{opacity:0;transform:translateY(-10px);max-height:0}}
9
+ */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;touch-action:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.cropper-container img{backface-visibility:hidden;display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-wrap-box,.cropper-canvas,.cropper-drag-box,.cropper-crop-box,.cropper-modal{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-wrap-box,.cropper-canvas{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:#3399ffbf;overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:calc(100% / 3);left:0;top:calc(100% / 3);width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:calc(100% / 3);top:0;width:calc(100% / 3)}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:before,.cropper-center:after{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media(min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media(min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media(min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}[data-v-a1dce3ee] .ProseMirror>*+*{margin-top:.75em}[data-v-a1dce3ee] .ProseMirror ol{padding:0 1rem;list-style:decimal!important}[data-v-a1dce3ee] .ProseMirror ul{padding:0 1rem;list-style:disc!important}.fade-in-down-enter-active[data-v-507c44cb]{animation:fadeInDown-507c44cb .3s ease-out}.fade-in-down-leave-active[data-v-507c44cb]{animation:fadeOutUp-507c44cb .3s ease-in;max-height:100px;overflow:hidden}.fade-in-down-leave-to[data-v-507c44cb]{opacity:0;transform:translateY(-10px);max-height:0;overflow:hidden}@keyframes fadeInDown-507c44cb{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeOutUp-507c44cb{0%{opacity:1;transform:translateY(0);max-height:100px}to{opacity:0;transform:translateY(-10px);max-height:0}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dcrackel/hematournamentui",
3
3
  "private": false,
4
- "version": "1.0.688",
4
+ "version": "1.0.691",
5
5
  "type": "module",
6
6
  "main": "dist/HemaTournamentUI-lib.umd.js",
7
7
  "module": "dist/HemaTournamentUI-lib.es.js",
@@ -108,7 +108,7 @@ export default {
108
108
  if (!fromDragId || !toDragId || String(fromDragId) === String(toDragId)) return;
109
109
  this.$emit('reorder:swap', { fromBoutId: fromDragId, toBoutId: toDragId });
110
110
  },
111
- onAssign(ids) { this.$emit('action:assignDirector', ids); },
111
+ onAssign(ids) { this.$emit('action:assignBout', ids); },
112
112
  },
113
113
  };
114
114
  </script>
@@ -59,41 +59,54 @@
59
59
  </section>
60
60
  </div>
61
61
 
62
+ <!-- Mobile -->
62
63
  <!-- Mobile -->
63
64
  <section
64
- class="relative flex md:hidden items-stretch border rounded-md bg-poolBox transition overflow-hidden"
65
+ class="relative flex md:hidden items-center border rounded-md bg-poolBox transition overflow-hidden"
65
66
  :class="[reorderMode ? 'cursor-grab ring-2 ring-dashed ring-slate-300' : '']"
66
67
  >
67
68
  <!-- main tappable area -->
68
- <div class="flex flex-1 items-center p-4" @click="onCardClick">
69
+ <div class="flex flex-1 items-center p-4 min-w-0" @click="onCardClick">
69
70
  <!-- left portrait or index when reordering -->
70
- <div v-if="!reorderMode" class="relative flex flex-col items-center">
71
+ <div v-if="!reorderMode" class="relative flex flex-col items-center flex-none">
71
72
  <img :src="fencer1Portrait" alt="Portrait" class="w-12 h-12 rounded-full"/>
72
73
  <div :class="`w-4 h-4 rounded-full bg-${card.fencer1.colorDot} relative -mt-4 ml-9 z-10`"></div>
73
74
  </div>
74
75
 
75
- <div v-if="reorderMode" class="flex flex-col items-center -mt-3 select-none">
76
+ <div v-if="reorderMode" class="flex flex-col items-center -mt-3 select-none flex-none">
76
77
  <BaseText text="bout" size="xs" color="quinary" weight="bold"/>
77
78
  <BaseText :text="`${(c.ids.orderIndex ?? 0) + 1}`" size="3xl" color="quaternary" weight="bold"/>
78
79
  </div>
79
80
 
80
81
  <!-- center -->
81
- <div class="text-center flex-1 mx-4 flex flex-col items-center justify-center leading-none">
82
+ <div class="text-center flex-1 mx-4 min-w-0 flex flex-col items-center justify-center leading-none">
82
83
  <div class="flex items-center justify-center">
83
- <div :class="`mr-2 bg-${card.fencer1.colorDot} w-3 h-3`"></div>
84
- <BaseText :text="c.fencer1.name" size="sm" color="quinary" weight="bold" class="leading-none"/>
84
+ <div :class="`mr-2 bg-${card.fencer1.colorDot} w-3 h-3 flex-none`"></div>
85
+ <BaseText
86
+ :text="c.fencer1.name"
87
+ size="sm"
88
+ color="quinary"
89
+ weight="bold"
90
+ class="leading-none truncate max-w-full"
91
+ />
85
92
  </div>
86
93
 
87
94
  <BaseText text="vs" size="xs" color="quaternary"/>
88
95
 
89
96
  <div class="flex items-center justify-center">
90
- <div :class="`mr-2 bg-${card.fencer2.colorDot} w-3 h-3`"></div>
91
- <BaseText :text="c.fencer2.name" size="sm" color="quinary" weight="bold" class="leading-none"/>
97
+ <div :class="`mr-2 bg-${card.fencer2.colorDot} w-3 h-3 flex-none`"></div>
98
+ <BaseText
99
+ :text="c.fencer2.name"
100
+ size="sm"
101
+ color="quinary"
102
+ weight="bold"
103
+ class="leading-none truncate max-w-full"
104
+ />
92
105
  </div>
93
106
  </div>
94
107
 
95
108
  <!-- right portrait -->
96
- <div class="relative w-12 h-12">
109
+ <div class="relative w-12 h-12 flex-none">
97
110
  <img :src="fencer2Portrait" alt="Portrait" class="w-12 h-12 rounded-full"/>
98
111
  <div :class="`absolute -mt-4 -right-1 w-4 h-4 rounded-full bg-${card.fencer2.colorDot} ring-2 ring-white`"></div>
99
112
  </div>
@@ -103,18 +116,15 @@
103
116
  <button
104
117
  v-if="isAdmin && isScheduled && !reorderMode"
105
118
  type="button"
106
- class="w-10 flex items-center justify-center border-l border-dropdownSelect bg-white/60 hover:bg-white"
119
+ class="flex-none w-10 h-full flex items-center justify-center bg-white/60 hover:bg-white"
107
120
  @click.stop="$emit('assign', c.ids)"
108
- aria-label="More actions"
121
+ aria-label="Assign director"
109
122
  title="Assign director"
110
123
  >
111
124
  <BaseIcon icon-name="fa-chevron-right" size="sm" color="quinary" hover="primary" />
112
125
  </button>
113
126
  </section>
114
127
 
115
-
116
-
117
-
118
128
  </section>
119
129
  </template>
120
130
 
@@ -1,44 +1,90 @@
1
1
  <template>
2
2
  <section v-if="listView" class="flex flex-col items-center">
3
- <div v-for="(bouts, roundName) in filteredBouts" :key="bouts[0].BoutId" class="w-full flex-col md:w-3/4 my-4">
4
- <BaseText class="my-5" color="primaryHighlight" size="sm" :text="roundName" weight="bold"/>
5
- <div v-for="bout in bouts" :key="bout.BoutId" class="mb-4 ">
6
- <section @click="handleBoutClick(bout)">
7
- <BoutCard :bout="bout"
8
- :hostingClubColors="hostingClubColors"
9
- :editMode="false"
10
- :reorderMode="false"
3
+
4
+ <!-- Assigned Bouts -->
5
+ <div v-if="hasAssignedBouts" class="w-full flex-col md:w-3/4 my-4">
6
+ <div class="flex flex-row justify-between">
7
+ <BaseText class="my-5" color="primaryHighlight" size="sm" text="Assigned Bouts" weight="bold"/>
8
+ <div class="flex mr-1">
9
+ <BaseText class="my-5 ml-5" color="primaryHighlight" size="sm" text="Assigned:"/>
10
+ <BaseText
11
+ :text="assignedBoutsToMe.length"
12
+ class="my-5 ml-2"
13
+ color="primaryHighlight"
14
+ size="sm"
15
+ weight="bold"
11
16
  />
12
- </section>
17
+ </div>
18
+ </div>
19
+ <div class="border-b border-dropdownSelect mb-5"></div>
20
+
21
+ <div v-for="bout in assignedBoutsToMe" :key="bout.BoutId" class="mb-4">
22
+ <BoutCard
23
+ :bout="bout"
24
+ :hostingClubColors="hostingClubColors"
25
+ :editMode="false"
26
+ :reorderMode="false"
27
+ :isAdmin="isAdmin"
28
+ @action:startBout="handleDirectingFromIds"
29
+ @action:resumeBout="handleDirectingFromIds"
30
+ @action:editBout="handleEditFromIds"
31
+ @action:assignBout="handleAssignBout"
32
+ />
33
+ </div>
34
+ </div>
35
+
36
+ <!-- Existing rounds -->
37
+ <div
38
+ v-for="(bouts, roundName) in filteredBouts"
39
+ :key="bouts[0].BoutId"
40
+ class="w-full flex-col md:w-3/4 my-4"
41
+ >
42
+ <BaseText class="my-5" color="primaryHighlight" size="sm" :text="roundName" weight="bold"/>
43
+
44
+ <div v-for="bout in bouts" :key="bout.BoutId" class="mb-4">
45
+ <BoutCard
46
+ :bout="bout"
47
+ :hostingClubColors="hostingClubColors"
48
+ :editMode="false"
49
+ :reorderMode="false"
50
+ :isAdmin="isAdmin"
51
+ @action:startBout="handleDirectingFromIds"
52
+ @action:resumeBout="handleDirectingFromIds"
53
+ @action:editBout="handleEditFromIds"
54
+ @action:assignBout="handleAssignBout"
55
+ />
13
56
  </div>
14
57
  </div>
15
58
  </section>
16
59
 
17
- <section v-if="!listView" class="flex w-full overflow-x-auto mt-4 scrollbar-thin">
60
+ <section v-else class="flex w-full overflow-x-auto mt-4 scrollbar-thin">
18
61
  <div class="min-w-full flex">
19
62
  <div v-for="(bouts, roundName) in groupedBouts.winnerBouts" :key="roundName">
20
- <TableauColumn :bouts="bouts"
21
- :hostingClubColors="hostingClubColors"
22
- :roundName="roundName"
23
- :bracketSize="bracketSize"
24
- :largeCards="largeCards"
25
- :isCountingBackwardsMaxScore="isCountingBackwardsMaxScore"
26
- @action:editBout="handleEditBout"
27
- @action:directingBout="handleDirectorBout"
63
+ <TableauColumn
64
+ :bouts="bouts"
65
+ :hostingClubColors="hostingClubColors"
66
+ :roundName="roundName"
67
+ :bracketSize="bracketSize"
68
+ :largeCards="largeCards"
69
+ :isCountingBackwardsMaxScore="isCountingBackwardsMaxScore"
70
+ @action:editBout="handleEditBout"
71
+ @action:directingBout="handleDirectorBout"
28
72
  />
29
73
  </div>
30
74
  </div>
31
- <!-- loser bracket-->
75
+
76
+ <!-- Loser bracket -->
32
77
  <div class="min-w-full flex">
33
78
  <div v-for="(bouts, roundName) in groupedBouts.loserBouts" :key="roundName">
34
- <TableauColumn :bouts="bouts"
35
- :hostingClubColors="hostingClubColors"
36
- :roundName="roundName"
37
- :bracketSize="bracketSize"
38
- :largeCards="largeCards"
39
- :isCountingBackwardsMaxScore="isCountingBackwardsMaxScore"
40
- @action:editBout="handleEditBout"
41
- @action:directingBout="handleDirectorBout"
79
+ <TableauColumn
80
+ :bouts="bouts"
81
+ :hostingClubColors="hostingClubColors"
82
+ :roundName="roundName"
83
+ :bracketSize="bracketSize"
84
+ :largeCards="largeCards"
85
+ :isCountingBackwardsMaxScore="isCountingBackwardsMaxScore"
86
+ @action:editBout="handleEditBout"
87
+ @action:directingBout="handleDirectorBout"
42
88
  />
43
89
  </div>
44
90
  </div>
@@ -52,56 +98,68 @@ import BoutCard from "../../../Organisms/Cards/BoutCard/BoutCard.vue";
52
98
  import BaseText from "../../../Atoms/Text/BaseText.vue";
53
99
 
54
100
  export default {
55
- name: 'Tableau',
56
- components: {BaseText, BoutCard, TableauBoutCard, TableauColumn},
101
+ name: "Tableau",
102
+ components: { BaseText, BoutCard, TableauBoutCard, TableauColumn },
103
+ emits: ["action:editBout", "action:directingBout", "action:assignBout"],
57
104
  props: {
58
- bouts: {
59
- type: Array,
60
- required: true
61
- },
62
- bracketSize: {
63
- type: String,
64
- required: true
65
- },
66
- hostingClubColors: {
67
- type: Object,
68
- required: true
105
+ bouts: { type: Array, required: true },
106
+ bracketSize: { type: String, required: true },
107
+ hostingClubColors: { type: Object, required: true },
108
+ largeCards: { type: Boolean, required: true },
109
+ listView: { type: Boolean, required: false },
110
+ isCountingBackwardsMaxScore: { type: Number, default: 0 },
111
+
112
+ // use role (already present upstream) instead of passing isAdmin
113
+ role: { type: String, default: "Admin" },
114
+
115
+ // needed for "Assigned Bouts" section
116
+ currentUserId: { type: [Number, String], default: null },
117
+ },
118
+ computed: {
119
+ isAdmin() {
120
+ return String(this.role || "").toLowerCase() === "admin";
69
121
  },
70
- largeCards: {
71
- type: Boolean,
72
- required: true
122
+
123
+ assignedBoutsToMe() {
124
+ const me = Number(this.currentUserId);
125
+ if (!me) return [];
126
+ return (this.bouts || [])
127
+ .filter(
128
+ (b) =>
129
+ Number(b.RefereeId) === me &&
130
+ String(b.Status || "").toLowerCase() !== "completed"
131
+ )
132
+ .slice()
133
+ .sort((a, b) => Number(a.DEBoutId ?? 0) - Number(b.DEBoutId ?? 0));
73
134
  },
74
- listView: {
75
- type: Boolean,
76
- required: false
135
+
136
+ hasAssignedBouts() {
137
+ return this.assignedBoutsToMe.length > 0;
77
138
  },
78
- isCountingBackwardsMaxScore: {
79
- type: Number,
80
- default: 0
81
- }
82
- },
83
- emits: ['action:editBout', 'action:directingBout'],
84
- computed: {
139
+
85
140
  groupedBouts() {
86
141
  const grouped = this.groupBoutsByRound(this.bouts);
87
142
 
88
- // Separate bouts into winnerBouts and loserBouts based on RoundLabel
89
- const {winnerBouts, loserBouts} = Object.entries(grouped).reduce(
143
+ const { winnerBouts, loserBouts } = Object.entries(grouped).reduce(
90
144
  (acc, [roundName, bouts]) => {
91
- if (roundName.includes('Consolation')) {
145
+ if (roundName.includes("Consolation")) {
92
146
  acc.loserBouts[roundName] = bouts;
93
147
  } else {
94
148
  acc.winnerBouts[roundName] = bouts;
95
149
  }
96
150
  return acc;
97
151
  },
98
- {winnerBouts: {}, loserBouts: {}}
152
+ { winnerBouts: {}, loserBouts: {} }
99
153
  );
100
154
 
101
- return {winnerBouts, loserBouts};
155
+ return { winnerBouts, loserBouts };
102
156
  },
157
+
103
158
  combinedBouts() {
104
- const combined = {...this.groupedBouts.winnerBouts, ...this.groupedBouts.loserBouts};
159
+ const combined = {
160
+ ...this.groupedBouts.winnerBouts,
161
+ ...this.groupedBouts.loserBouts,
162
+ };
105
163
  return Object.keys(combined)
106
164
  .sort()
107
165
  .reduce((acc, roundName) => {
@@ -109,21 +167,20 @@ export default {
109
167
  return acc;
110
168
  }, {});
111
169
  },
170
+
112
171
  filteredBouts() {
113
172
  return Object.keys(this.combinedBouts)
114
173
  .sort((a, b) => {
115
174
  const priority = {
116
175
  Final: 1,
117
176
  "Third Place Match": 2,
118
- Semifinal: 3
177
+ Semifinal: 3,
119
178
  };
120
179
 
121
180
  const priorityA = priority[a] || 0;
122
181
  const priorityB = priority[b] || 0;
123
182
 
124
- if (priorityA || priorityB) {
125
- return priorityA - priorityB;
126
- }
183
+ if (priorityA || priorityB) return priorityA - priorityB;
127
184
 
128
185
  const numA = parseInt(a.match(/\d+/)?.[0] || 0, 10);
129
186
  const numB = parseInt(b.match(/\d+/)?.[0] || 0, 10);
@@ -131,69 +188,72 @@ export default {
131
188
  return numB - numA;
132
189
  })
133
190
  .reduce((acc, roundName) => {
134
- const filteredBouts = this.combinedBouts[roundName]
191
+ const filtered = this.combinedBouts[roundName]
135
192
  .filter(
136
- bout =>
137
- bout.Person1?.DisplayName !== 'BYE' &&
138
- bout.Person2?.DisplayName !== 'BYE' &&
139
- bout.Status !== 'Completed'
193
+ (bout) =>
194
+ bout.Person1?.DisplayName !== "BYE" &&
195
+ bout.Person2?.DisplayName !== "BYE" &&
196
+ bout.Status !== "Completed"
140
197
  )
141
198
  .sort((a, b) => a.DEBoutId - b.DEBoutId);
142
199
 
143
- if (filteredBouts.length) {
144
- acc[roundName] = filteredBouts;
145
- }
200
+ if (filtered.length) acc[roundName] = filtered;
146
201
  return acc;
147
202
  }, {});
148
203
  },
149
204
  },
205
+
150
206
  methods: {
151
- handleBoutClick(bout) {
152
- if (bout.Status === 'Completed') {
153
- this.$emit('action:editBout', bout);
154
- } else {
155
- this.$emit('action:directingBout', bout);
156
- }
207
+ // --- helpers ---
208
+ _findBoutByIds(idsOrBout) {
209
+ // BoutCard emits ids for start/resume/edit; assign emits ids too.
210
+ // normalize to actual bout object
211
+ if (!idsOrBout) return null;
212
+ if (idsOrBout.BoutId && idsOrBout.Person1) return idsOrBout; // already a bout-ish object
213
+
214
+ const boutId = idsOrBout?.BoutId ?? idsOrBout?.boutId;
215
+ if (!boutId) return null;
216
+ return (this.bouts || []).find((b) => String(b.BoutId) === String(boutId)) || null;
157
217
  },
218
+
219
+ // Assign button from BoutCard (inactive scheduled variant)
220
+ handleAssignBout(ids) {
221
+ const bout = this._findBoutByIds(ids);
222
+ if (!bout) return;
223
+ this.$emit("action:assignBout", bout);
224
+ },
225
+
226
+ // Start/Resume from BoutCard
227
+ handleDirectingFromIds(ids) {
228
+ const bout = this._findBoutByIds(ids);
229
+ if (!bout) return;
230
+ this.$emit("action:directingBout", bout);
231
+ },
232
+
233
+ // Edit from BoutCard
234
+ handleEditFromIds(ids) {
235
+ const bout = this._findBoutByIds(ids);
236
+ if (!bout) return;
237
+ this.$emit("action:editBout", bout);
238
+ },
239
+
240
+ // TableauColumn / non-list view already emits bout objects
158
241
  handleEditBout(bout) {
159
- this.$emit('action:editBout', bout)
242
+ this.$emit("action:editBout", bout);
160
243
  },
161
244
  handleDirectorBout(bout) {
162
- this.$emit('action:directingBout', bout)
245
+ this.$emit("action:directingBout", bout);
163
246
  },
247
+
164
248
  groupBoutsByRound(bouts) {
165
- return bouts.reduce((acc, bout) => {
166
- if (!acc[bout.RoundLabel]) {
167
- acc[bout.RoundLabel] = [];
168
- }
169
- acc[bout.RoundLabel].push(bout);
249
+ return (bouts || []).reduce((acc, bout) => {
250
+ const key = bout.RoundLabel || "Unknown Round";
251
+ if (!acc[key]) acc[key] = [];
252
+ acc[key].push(bout);
170
253
  return acc;
171
254
  }, {});
172
255
  },
173
- }
256
+ },
174
257
  };
175
258
  </script>
176
259
 
177
- <style scoped>
178
- /* width */
179
- ::-webkit-scrollbar {
180
- width: 15px;
181
- height: 15px;
182
- }
183
-
184
- /* Track */
185
- ::-webkit-scrollbar-track {
186
- background: #f6fafd;
187
- }
188
-
189
- /* Handle */
190
- ::-webkit-scrollbar-thumb {
191
- background: #d5e4ee;
192
- border-radius: 5px;
193
- }
194
-
195
- /* Handle on hover */
196
- ::-webkit-scrollbar-thumb:hover {
197
- background: #c3cce0;
198
- }
199
- </style>
@@ -1,4 +1,5 @@
1
1
  import Bracket from './Bracket.vue';
2
+ import getDirectors from '../../../../mocks/getDirectors.js';
2
3
  //import getDEWithBouts from '../../../../mocks/getDEWithBouts.js';
3
4
  import getDEWithBouts6Fencers from '../../../../mocks/getDeBouts-6fencers.js';
4
5
  import getDEWithBouts12Fencers from '../../../../mocks/getDeBouts-12fencers.js';
@@ -17,7 +18,9 @@ export default {
17
18
  eventRules: getDEWithBouts.eventRules,
18
19
  hostingClubColors: getDEWithBouts.hostingClubColors,
19
20
  connectedToServer: true,
20
- role: 'admin'
21
+ role: 'admin',
22
+ directors: getDirectors,
23
+ currentUserId: 79, // optional but useful if you're showing "Assigned Bouts"
21
24
  },
22
25
  argTypes: {
23
26
  bouts: {
@@ -34,7 +37,9 @@ export default {
34
37
  },
35
38
  role: {
36
39
  control: String
37
- }
40
+ },
41
+ directors: { control: 'object' },
42
+ currentUserId: { control: 'number' },
38
43
  },
39
44
  };
40
45
 
@@ -45,7 +50,9 @@ export const Default = {
45
50
  hostingClubColors: getDEWithBouts12Fencers.hostingClubColors,
46
51
  connectedToServer: true,
47
52
  status: 'de',
48
- role: 'Admin'
53
+ role: 'Admin',
54
+ directors: getDirectors,
55
+ currentUserId: 79,
49
56
  }
50
57
  };
51
58
 
@@ -55,7 +62,9 @@ export const TableOfEight = {
55
62
  eventRules: getDEWithBouts6Fencers.eventRules,
56
63
  hostingClubColors: getDEWithBouts6Fencers.hostingClubColors,
57
64
  connectedToServer: true,
58
- status: 'de'
65
+ status: 'de',
66
+ directors: getDirectors,
67
+ currentUserId: 79,
59
68
  }
60
69
  };
61
70
 
@@ -65,7 +74,9 @@ export const TableWithTwentyTwo = {
65
74
  eventRules: getDEWithBouts22Fencers.eventRules,
66
75
  hostingClubColors: getDEWithBouts22Fencers.hostingClubColors,
67
76
  connectedToServer: true,
68
- status: 'de'
77
+ status: 'de',
78
+ directors: getDirectors,
79
+ currentUserId: 79,
69
80
  }
70
81
  };
71
82
 
@@ -75,7 +86,9 @@ export const tableOfThirtyTwo = {
75
86
  eventRules: getDEWithBouts.eventRules,
76
87
  hostingClubColors: getDEWithBouts.hostingClubColors,
77
88
  connectedToServer: true,
78
- status: 'de'
89
+ status: 'de',
90
+ directors: getDirectors,
91
+ currentUserId: 79,
79
92
  }
80
93
  };
81
94
 
@@ -85,7 +98,9 @@ export const tableOfFourtyTwo = {
85
98
  eventRules: getDEWithBout42Fencers.eventRules,
86
99
  hostingClubColors: getDEWithBout42Fencers.hostingClubColors,
87
100
  connectedToServer: true,
88
- status: 'de'
101
+ status: 'de',
102
+ directors: getDirectors,
103
+ currentUserId: 79,
89
104
  }
90
105
  };
91
106
 
@@ -95,7 +110,9 @@ export const tableOfSixtyFour = {
95
110
  eventRules: getDEWithBouts67Fencers.eventRules,
96
111
  hostingClubColors: getDEWithBouts67Fencers.hostingClubColors,
97
112
  connectedToServer: true,
98
- status: 'de'
113
+ status: 'de',
114
+ directors: getDirectors,
115
+ currentUserId: 79,
99
116
  }
100
117
  };
101
118
 
@@ -105,7 +122,9 @@ export const tableOfOneHundredTwentyEight = {
105
122
  eventRules: getDEWithBouts128Fencers.eventRules,
106
123
  hostingClubColors: getDEWithBouts128Fencers.hostingClubColors,
107
124
  connectedToServer: true,
108
- status: 'de'
125
+ status: 'de',
126
+ directors: getDirectors,
127
+ currentUserId: 79,
109
128
  }
110
129
  };
111
130
 
@@ -115,6 +134,8 @@ export const noBoutsYet = {
115
134
  eventRules: getDEWithBouts22Fencers.eventRules,
116
135
  hostingClubColors: getDEWithBouts22Fencers.hostingClubColors,
117
136
  connectedToServer: true,
118
- status: 'live'
137
+ status: 'live',
138
+ directors: getDirectors,
139
+ currentUserId: 79,
119
140
  }
120
141
  };