Skip to content

Commit efe05dc

Browse files
authored
Merge pull request #4105 from nextcloud/enh/group-overview
poll overview for groups
2 parents f85a5b6 + 07dd9e6 commit efe05dc

7 files changed

Lines changed: 83 additions & 8 deletions

File tree

lib/Controller/PageController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function __construct(
4444
#[FrontpageRoute(verb: 'GET', url: '/combo', postfix: 'combo')]
4545
#[FrontpageRoute(verb: 'GET', url: '/not-found', postfix: 'notFound')]
4646
#[FrontpageRoute(verb: 'GET', url: '/list/{category}', postfix: 'list')]
47+
#[FrontpageRoute(verb: 'GET', url: '/group/{slug}', postfix: 'group')]
4748
public function index(): TemplateResponse {
4849
Util::addScript(AppConstants::APP_ID, 'polls-main');
4950
$this->eventDispatcher->dispatchTyped(new LoadAdditionalScriptsEvent());

lib/Db/PollGroup.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ public function hasPoll(int $pollId): bool {
6868
return in_array($pollId, $polls, true);
6969
}
7070

71+
public function getSlug(): string {
72+
// sanitize the title to remove any unwanted characters
73+
$slug = preg_replace('/[^a-zA-Z0-9\s]/', '', $this->getTitle());
74+
// in case the title is empty, use a default slug
75+
if ($slug === '') {
76+
$slug = 'group';
77+
}
78+
return strtolower(str_replace(' ', '-', $slug)) . '-' . $this->getId();
79+
}
80+
7181
// alias of getOwner()
7282
public function getUserId(): string {
7383
return $this->getOwner();
@@ -93,6 +103,7 @@ public function jsonSerialize(): array {
93103
'title' => $this->getTitle(),
94104
'titleExt' => $this->getTitleExt(),
95105
'pollIds' => $this->getPollIds(),
106+
'slug' => $this->getSlug(),
96107
];
97108
}
98109
}

src/router.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,19 @@ const routes: RouteRecordRaw[] = [
9494
votePage: false,
9595
},
9696
},
97+
{
98+
path: '/group/:slug',
99+
components: {
100+
default: List,
101+
navigation: Navigation,
102+
},
103+
props: true,
104+
name: 'group',
105+
meta: {
106+
publicPage: false,
107+
votePage: false,
108+
},
109+
},
97110
{
98111
path: '/combo',
99112
components: {

src/stores/polls.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export type PollGroup = {
6060
title: string
6161
titleExt: string
6262
pollIds: number[]
63+
slug: string
6364
}
6465

6566
export type PollCategoryList = Record<FilterType, PollCategory>
@@ -285,6 +286,7 @@ export const usePollsStore = defineStore('polls', {
285286
pollsWithGroups(state: PollList): Poll[] {
286287
return state.polls.filter((poll: Poll) => poll.pollGroups.length > 0)
287288
},
289+
288290
currentCategory(state: PollList): PollCategory {
289291
const sessionStore = useSessionStore()
290292

@@ -297,10 +299,34 @@ export const usePollsStore = defineStore('polls', {
297299
return state.categories[FilterType.Relevant]
298300
},
299301

302+
currentGroup(state: PollList): PollGroup | undefined {
303+
const sessionStore = useSessionStore()
304+
if (sessionStore.route.name === 'group') {
305+
return state.pollGroups.find(
306+
(group) => group.slug === sessionStore.route.params.slug,
307+
)
308+
}
309+
return undefined
310+
},
311+
312+
groupPolls(state: PollList): Poll[] {
313+
if (!this.currentGroup) {
314+
return []
315+
}
316+
return state.polls.filter((poll) =>
317+
this.currentGroup?.pollIds.includes(poll.id),
318+
)
319+
},
320+
300321
/*
301322
* polls list, filtered by current category and sorted
302323
*/
303324
pollsFilteredSorted(state: PollList): Poll[] {
325+
const sessionStore = useSessionStore()
326+
if (sessionStore.route.name === 'group') {
327+
return this.groupPolls
328+
}
329+
304330
return orderBy(
305331
state.polls.filter((poll: Poll) =>
306332
this.currentCategory?.filterCondition(poll),

src/stores/session.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ interface RouteParams {
2424
id: number
2525
token: string
2626
type: FilterType
27+
slug: string
2728
}
2829

2930
export type Route = {
@@ -121,6 +122,7 @@ export const useSessionStore = defineStore('session', {
121122
id: 0,
122123
token: '',
123124
type: FilterType.Relevant,
125+
slug: '',
124126
},
125127
},
126128
userStatus: {
@@ -227,6 +229,7 @@ export const useSessionStore = defineStore('session', {
227229
this.route.params.id = payload.params.id as unknown as number
228230
this.route.params.token = payload.params.token as string
229231
this.route.params.type = payload.params.type as FilterType
232+
this.route.params.slug = payload.params.slug as string
230233
},
231234

232235
// Share store

src/views/Navigation.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ onMounted(() => {
194194
:name="pollGroup.title"
195195
:title="pollGroup.titleExt"
196196
:allow-collapse="sessionStore.appSettings.navigationPollsInList"
197+
:to="{
198+
name: 'group',
199+
params: { slug: pollGroup.slug },
200+
}"
197201
:open="false">
198202
<template #icon>
199203
<GroupIcon :size="iconSize" />
@@ -219,8 +223,8 @@ onMounted(() => {
219223
"
220224
class="force-not-active"
221225
:to="{
222-
name: 'list',
223-
params: { type: pollGroup.id },
226+
name: 'group',
227+
params: { slug: pollGroup.slug },
224228
}"
225229
:name="t('polls', 'Show all')">
226230
<template #icon>

src/views/PollList.vue

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,16 @@ const sessionStore = useSessionStore()
3030
const router = useRouter()
3131
const route = useRoute()
3232
33-
const title = computed(
34-
() => pollsStore.categories[route.params.type as FilterType].titleExt,
35-
)
33+
const title = computed(() => {
34+
if (route.name === 'group') {
35+
return (
36+
pollsStore.currentGroup?.titleExt
37+
|| pollsStore.currentGroup?.title
38+
|| t('polls', 'Group without title')
39+
)
40+
}
41+
return pollsStore.categories[route.params.type as FilterType].titleExt
42+
})
3643
3744
const showMore = computed(
3845
() =>
@@ -56,12 +63,22 @@ const infoLoaded = computed(() =>
5663
},
5764
),
5865
)
59-
const description = computed(
60-
() => pollsStore.categories[route.params.type as FilterType].description,
61-
)
66+
67+
const description = computed(() => {
68+
if (route.name === 'group') {
69+
return (
70+
pollsStore.currentGroup?.description
71+
|| t('polls', 'Group without description')
72+
)
73+
}
74+
75+
return pollsStore.categories[route.params.type as FilterType].description
76+
})
77+
6278
const emptyPollListnoPolls = computed(
6379
() => pollsStore.pollsFilteredSorted.length < 1,
6480
)
81+
6582
const windowTitle = computed(() => `${t('polls', 'Polls')} - ${title.value}`)
6683
6784
const emptyContent = computed(() => {

0 commit comments

Comments
 (0)