From fcea7adee63ee456797cc0e53bf7d80c274740c6 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Tue, 24 Mar 2026 11:15:40 +0100 Subject: [PATCH 01/11] use NcModal trough transparent custom component Signed-off-by: dartcafe --- .../Actions/modules/ActionSendConfirmed.vue | 2 +- src/components/Base/modules/ButtonModal.vue | 2 +- src/components/Base/modules/CustomNcModal.vue | 27 +++++++++++++++++++ src/components/Modals/OptionsAddModal.vue | 2 +- src/components/Options/OptionMenu.vue | 2 +- src/components/Options/OptionsTextAddBulk.vue | 2 +- src/components/Shares/SharesList.vue | 2 +- 7 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 src/components/Base/modules/CustomNcModal.vue diff --git a/src/components/Actions/modules/ActionSendConfirmed.vue b/src/components/Actions/modules/ActionSendConfirmed.vue index 63267d9762..a15979978e 100644 --- a/src/components/Actions/modules/ActionSendConfirmed.vue +++ b/src/components/Actions/modules/ActionSendConfirmed.vue @@ -8,7 +8,7 @@ import { useRoute } from 'vue-router' import { ref } from 'vue' import { t, n } from '@nextcloud/l10n' -import NcModal from '@nextcloud/vue/components/NcModal' +import NcModal from '../../Base/modules/CustomNcModal.vue' import NcButton from '@nextcloud/vue/components/NcButton' import EmailCheckIcon from 'vue-material-design-icons/EmailCheckOutline.vue' // view-comfy-outline diff --git a/src/components/Base/modules/ButtonModal.vue b/src/components/Base/modules/ButtonModal.vue index 02c09af30c..1f25d55413 100644 --- a/src/components/Base/modules/ButtonModal.vue +++ b/src/components/Base/modules/ButtonModal.vue @@ -7,7 +7,7 @@ import { t } from '@nextcloud/l10n' import NcButton, { ButtonVariant } from '@nextcloud/vue/components/NcButton' -import NcModal from '@nextcloud/vue/components/NcModal' +import NcModal from '../../Base/modules/CustomNcModal.vue' import NcActionButton from '@nextcloud/vue/components/NcActionButton' import NcAppNavigationNew from '@nextcloud/vue/components/NcAppNavigationNew' diff --git a/src/components/Base/modules/CustomNcModal.vue b/src/components/Base/modules/CustomNcModal.vue new file mode 100644 index 0000000000..2c2e89922b --- /dev/null +++ b/src/components/Base/modules/CustomNcModal.vue @@ -0,0 +1,27 @@ + + + + + + + diff --git a/src/components/Modals/OptionsAddModal.vue b/src/components/Modals/OptionsAddModal.vue index 00096b2d18..daa955bbb4 100644 --- a/src/components/Modals/OptionsAddModal.vue +++ b/src/components/Modals/OptionsAddModal.vue @@ -7,7 +7,7 @@ import { ref, onMounted, onUnmounted } from 'vue' import { t } from '@nextcloud/l10n' import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent' -import NcModal from '@nextcloud/vue/components/NcModal' +import NcModal from '../Base/modules/CustomNcModal.vue' import { subscribe, unsubscribe } from '@nextcloud/event-bus' import DatePollIcon from 'vue-material-design-icons/CalendarBlankOutline.vue' diff --git a/src/components/Options/OptionMenu.vue b/src/components/Options/OptionMenu.vue index 5fb4a96aeb..0b76b74f39 100644 --- a/src/components/Options/OptionMenu.vue +++ b/src/components/Options/OptionMenu.vue @@ -9,7 +9,7 @@ import { t } from '@nextcloud/l10n' import NcActions from '@nextcloud/vue/components/NcActions' import NcActionButton from '@nextcloud/vue/components/NcActionButton' -import NcModal from '@nextcloud/vue/components/NcModal' +import NcModal from '../Base/modules/CustomNcModal.vue' import NcActionText from '@nextcloud/vue/components/NcActionText' import CloneDateIcon from 'vue-material-design-icons/CalendarMultiple.vue' diff --git a/src/components/Options/OptionsTextAddBulk.vue b/src/components/Options/OptionsTextAddBulk.vue index 15aa63774d..aed061f25a 100644 --- a/src/components/Options/OptionsTextAddBulk.vue +++ b/src/components/Options/OptionsTextAddBulk.vue @@ -8,7 +8,7 @@ import { ref } from 'vue' import { showError, showSuccess } from '@nextcloud/dialogs' import { t } from '@nextcloud/l10n' -import NcModal from '@nextcloud/vue/components/NcModal' +import NcModal from '../Base/modules/CustomNcModal.vue' import NcActions from '@nextcloud/vue/components/NcActions' import NcActionButton from '@nextcloud/vue/components/NcActionButton' import NcButton from '@nextcloud/vue/components/NcButton' diff --git a/src/components/Shares/SharesList.vue b/src/components/Shares/SharesList.vue index 79999b5e11..63c59a1215 100644 --- a/src/components/Shares/SharesList.vue +++ b/src/components/Shares/SharesList.vue @@ -8,7 +8,7 @@ import { ref } from 'vue' import { t } from '@nextcloud/l10n' import { showError } from '@nextcloud/dialogs' -import NcModal from '@nextcloud/vue/components/NcModal' +import NcModal from '../Base/modules/CustomNcModal.vue' import ShareIcon from 'vue-material-design-icons/ShareVariantOutline.vue' From 5debbb59af18f76fd29f5785905890d06cde13bc Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sun, 29 Mar 2026 16:07:02 +0200 Subject: [PATCH 02/11] updating registration modal Signed-off-by: dartcafe --- src/assets/scss/globals.scss | 42 ---- src/assets/scss/hacks.scss | 13 -- src/assets/scss/vars.scss | 3 + .../Actions/modules/ActionRegister.vue | 8 +- src/components/Base/modules/CustomNcModal.vue | 41 +++- src/components/Modals/OptionsAddModal.vue | 6 +- src/components/Poll/MarkDownDescription.vue | 16 ++ src/components/Public/PublicRegisterModal.vue | 206 +++++++----------- src/helpers/modules/InlineLink.ts | 63 ++++++ 9 files changed, 208 insertions(+), 190 deletions(-) create mode 100644 src/helpers/modules/InlineLink.ts diff --git a/src/assets/scss/globals.scss b/src/assets/scss/globals.scss index 148b89d099..cadfe5dcb7 100644 --- a/src/assets/scss/globals.scss +++ b/src/assets/scss/globals.scss @@ -19,48 +19,6 @@ padding: 0 !important; } -// global modal settings -.modal__content { - padding: 14px; - display: flex; - flex-direction: column; - color: var(--color-main-text); -} - -.modal__buttons__spacer { - flex: 1; -} - -.modal__buttons { - display: flex; - gap: 8px; - justify-content: flex-end; - flex-wrap: wrap-reverse; - align-items: center; - margin-top: 36px; - - .left { - display: flex; - flex: 1; - gap: 8px; - } - - .right { - display: flex; - flex: 0; - justify-content: flex-end; - gap: 8px; - } - - .button { - margin-inline: 10px 0; - } -} - -.modal__buttons__link { - text-decoration: underline; -} - .sortable { * { cursor: grab; diff --git a/src/assets/scss/hacks.scss b/src/assets/scss/hacks.scss index 5f451b8c96..2da8a3c7b3 100644 --- a/src/assets/scss/hacks.scss +++ b/src/assets/scss/hacks.scss @@ -21,20 +21,11 @@ height: var(--avatar-size); } -// h2 in notecard gets a margin-top of -6px instead of 24px for better alignment -.notecard h2 { - margin-top: -6px; -} - // relative position to be able to get sticky toolbar .app-content { position: relative !important; } -.app-sidebar { - top: 0 !important; -} - .action-item.action-item--single.app-navigation-toggle.undefined.has-tooltip { top: 4px; margin-inline-end: -50px; @@ -56,7 +47,3 @@ display: inline !important; } } - -.modal-wrapper .modal-container { - overflow: scroll !important; -} diff --git a/src/assets/scss/vars.scss b/src/assets/scss/vars.scss index 4cc3b1de8b..78f4d5896f 100644 --- a/src/assets/scss/vars.scss +++ b/src/assets/scss/vars.scss @@ -8,6 +8,7 @@ --cap-width: 49rem; --shadow-height: 0.7rem; --shadow-height-inverted: -0.7rem; + --scroll-fade-shadow: rgba(0, 0, 0, 0.1); --color-polls-foreground-yes: #2d7b41; --color-polls-foreground-no: #db0606; --color-polls-foreground-maybe: #a37200; @@ -26,6 +27,7 @@ --color-polls-background-no: #451c1c; --color-polls-background-maybe: #2e2914; --container-background-light: #14262e; + --scroll-fade-shadow: rgba(255, 255, 255, 0.15); } } @@ -37,4 +39,5 @@ --color-polls-background-no: #451c1c; --color-polls-background-maybe: #2e2914; --container-background-light: #14262e; + --scroll-fade-shadow: rgba(255, 255, 255, 0.15); } diff --git a/src/components/Actions/modules/ActionRegister.vue b/src/components/Actions/modules/ActionRegister.vue index d451e78176..51fa8e6eef 100644 --- a/src/components/Actions/modules/ActionRegister.vue +++ b/src/components/Actions/modules/ActionRegister.vue @@ -8,13 +8,15 @@ import { ref } from 'vue' import { t } from '@nextcloud/l10n' import NcButton from '@nextcloud/vue/components/NcButton' -import NcModal from '@nextcloud/vue/components/NcModal' +import NcModal from '../../Base/modules/CustomNcModal.vue' import PublicRegisterModal from '../../Public/PublicRegisterModal.vue' +import { usePollStore } from '@/stores/poll' const caption = t('polls', 'Register') -const showRegistration = ref(false) +const showRegistration = ref(true) const registerModalSize = 'large' +const pollStore = usePollStore() - diff --git a/src/components/Modals/OptionsAddModal.vue b/src/components/Modals/OptionsAddModal.vue index daa955bbb4..a9b7627d0a 100644 --- a/src/components/Modals/OptionsAddModal.vue +++ b/src/components/Modals/OptionsAddModal.vue @@ -34,7 +34,7 @@ onUnmounted(() => { diff --git a/src/helpers/modules/InlineLink.ts b/src/helpers/modules/InlineLink.ts new file mode 100644 index 0000000000..b95c47f5b8 --- /dev/null +++ b/src/helpers/modules/InlineLink.ts @@ -0,0 +1,63 @@ +/** + * SPDX-FileCopyrightText: 2026 Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { h } from 'vue' + +/** + * Renders a translated string where [link]...[/link] is replaced by an anchor element. + * Square brackets are used so t() does not strip the markers as HTML tags. + * + * Usage: + * + * + * + */ +const InlineLink = { + inheritAttrs: false, + + props: { + text: { + type: String, + default: '', + }, + href: { + type: String, + default: '#', + }, + target: { + type: String, + default: null, + }, + }, + + setup( + props: { text: string; href: string; target: string | null }, + { attrs }: { attrs: Record }, + ) { + return () => { + const match = props.text.match( + /^([\s\S]*)\[link\]([\s\S]*)\[\/link\]([\s\S]*)$/, + ) + + if (!match) { + return h('span', props.text) + } + + const [, before, linkText, after] = match + + return h('span', [ + before, + h( + 'a', + { href: props.href, target: props.target, style: 'text-decoration: revert', ...attrs }, + linkText, + ), + after, + ]) + } + }, +} + +export { InlineLink } From f77d62f84d9dd4fef0e006e49d962f1a862759fd Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sun, 29 Mar 2026 21:09:45 +0200 Subject: [PATCH 03/11] tidy Signed-off-by: dartcafe --- lib/Controller/PublicController.php | 2 +- lib/Controller/ShareApiController.php | 2 +- lib/Service/ShareService.php | 12 ------------ 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/Controller/PublicController.php b/lib/Controller/PublicController.php index 1799088a46..a813857972 100644 --- a/lib/Controller/PublicController.php +++ b/lib/Controller/PublicController.php @@ -491,7 +491,7 @@ public function deleteEmailAddress(string $token): JSONResponse { #[FrontpageRoute(verb: 'POST', url: '/s/{token}/register')] public function register(string $token, string $displayName, string $emailAddress = '', string $timeZone = ''): JSONResponse { return $this->response(fn () => [ - 'share' => $this->shareService->register($token, $displayName, $emailAddress, $timeZone), + 'share' => $this->shareService->registerGuest($token, $displayName, $emailAddress, $timeZone), ], Http::STATUS_CREATED); } diff --git a/lib/Controller/ShareApiController.php b/lib/Controller/ShareApiController.php index be996e5025..285848ee3c 100644 --- a/lib/Controller/ShareApiController.php +++ b/lib/Controller/ShareApiController.php @@ -67,7 +67,7 @@ public function get(string $token): DataResponse { #[ApiRoute(verb: 'POST', url: 'api/v1.0/s/{token}/register')] public function register(string $token, string $displayName, string $emailAddress = '', string $timeZone = ''): DataResponse { return $this->response(fn () => [ - 'share' => $this->shareService->register($token, $displayName, $emailAddress, $timeZone), + 'share' => $this->shareService->registerGuest($token, $displayName, $emailAddress, $timeZone), ], Http::STATUS_CREATED); } diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index b4bbdb0600..1a55531a6c 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -360,18 +360,6 @@ private function convertDependingObjects(string $userId, string $replacementId, $this->commentMapper->renameUserId($userId, $replacementId, $pollId); } - /** - * @deprecated Use registerGuest() instead - */ - public function register( - string $publicShareToken, - string $displayName, - string $emailAddress = '', - string $timeZone = '', - ): Share { - return $this->registerGuest($publicShareToken, $displayName, $emailAddress, $timeZone); - } - /** * Delete or restore share by Token * @param string $token Share of token to delete From 0eb5b329aeffef4f6729b353b622ffcca319b86f Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sun, 29 Mar 2026 21:10:01 +0200 Subject: [PATCH 04/11] hide public-user-menu Signed-off-by: dartcafe --- src/App.vue | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/App.vue b/src/App.vue index 9146dd5b26..f8c8608ec3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -136,6 +136,11 @@ onUnmounted(() => { diff --git a/src/components/Actions/modules/ActionRegister.vue b/src/components/Actions/modules/ActionRegister.vue deleted file mode 100644 index 51fa8e6eef..0000000000 --- a/src/components/Actions/modules/ActionRegister.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - - - diff --git a/src/components/Cards/CardRegister.vue b/src/components/Cards/CardRegister.vue deleted file mode 100644 index 4a4fd351c0..0000000000 --- a/src/components/Cards/CardRegister.vue +++ /dev/null @@ -1,40 +0,0 @@ - - - - - diff --git a/src/components/Cards/VoteInfoCards.vue b/src/components/Cards/VoteInfoCards.vue index 6e2875eef7..42ef9a65bf 100644 --- a/src/components/Cards/VoteInfoCards.vue +++ b/src/components/Cards/VoteInfoCards.vue @@ -9,7 +9,6 @@ import CardAddProposals from './CardAddProposals.vue' import CardClosedPoll from './CardClosedPoll.vue' import CardLimitedVotes from './CardLimitedVotes.vue' import CardLocked from './CardLocked.vue' -import CardRegister from './CardRegister.vue' import CardSendConfirmations from './CardSendConfirmations.vue' import CardTimezone from './CardTimezone.vue' import CardUnpublishedPoll from './CardUnpublishedPoll.vue' @@ -17,12 +16,10 @@ import CardUnpublishedPoll from './CardUnpublishedPoll.vue' import { usePollStore } from '../../stores/poll' import { useOptionsStore } from '../../stores/options' import { useSharesStore } from '../../stores/shares' -import { useSessionStore } from '../../stores/session' const pollStore = usePollStore() const optionsStore = useOptionsStore() const sharesStore = useSharesStore() -const sessionStore = useSessionStore() const showTimezoneHint = computed( () => @@ -60,16 +57,6 @@ const showLimitCard = computed( && (pollStore.configuration.maxVotesPerOption || pollStore.configuration.maxVotesPerUser), ) -const showRegisterCard = computed( - () => - sessionStore.route.name === 'publicVote' - && ['public', 'email', 'contact'].includes( - pollStore.currentUserStatus.userRole, - ) - && !pollStore.isClosed - && !pollStore.currentUserStatus.isLocked - && !!pollStore.id, -) diff --git a/src/router.ts b/src/router.ts index 431ca8bc22..551bbf1b19 100644 --- a/src/router.ts +++ b/src/router.ts @@ -67,6 +67,7 @@ const Forbidden = () => import('./views/Forbidden.vue') const List = () => import('./views/PollList.vue') const NotFound = () => import('./views/NotFound.vue') const Vote = () => import('./views/Vote.vue') +const PublicRegisterView = () => import('./views/PublicRegisterView.vue') const SideBar = () => import('./views/SideBar.vue') const SideBarPollGroup = () => import('./views/SideBarPollGroup.vue') @@ -160,6 +161,19 @@ const routes: RouteRecordRaw[] = [ votePage: true, }, }, + { + name: 'publicRegister', + path: '/s/:token/register', + components: { + default: PublicRegisterView, + }, + beforeEnter: validateToken, + props: true, + meta: { + publicPage: true, + registerPage: true, + }, + }, { name: 'root', path: '/', @@ -243,6 +257,30 @@ router.beforeResolve(async (to: RouteLocationNormalized) => { await pollsStore.load(!watcherActive) } + if (to.meta.registerPage) { + const pollStore = usePollStore() + + try { + await pollStore.load() + } catch { + return { name: 'notfound' } + } + + // If the user no longer needs to register, redirect to the vote page + const needsRegistration = + pollStore.currentUserStatus.userRole === 'public' + && !pollStore.isClosed + && !pollStore.currentUserStatus.isLocked + + if (!needsRegistration) { + return { + name: 'publicVote', + params: { token: to.params.token }, + replace: true, + } + } + } + if (to.meta.votePage) { const pollStore = usePollStore() const votesStore = useVotesStore() @@ -255,6 +293,21 @@ router.beforeResolve(async (to: RouteLocationNormalized) => { return { name: 'notfound' } } + // Redirect unregistered public users to the registration page + if (to.name === 'publicVote') { + const needsRegistration = + pollStore.currentUserStatus.userRole === 'public' + && !pollStore.isClosed + && !pollStore.currentUserStatus.isLocked + + if (needsRegistration) { + return { + name: 'publicRegister', + params: { token: to.params.token }, + } + } + } + await Promise.allSettled([ votesStore.load(), optionsStore.load(), diff --git a/src/stores/poll.ts b/src/stores/poll.ts index 541bf88c70..24534b9773 100644 --- a/src/stores/poll.ts +++ b/src/stores/poll.ts @@ -266,7 +266,7 @@ export const usePollStore = defineStore('poll', { try { const response = await (() => { - if (sessionStore.route.name === 'publicVote') { + if (sessionStore.route.name === 'publicVote' || sessionStore.route.name === 'publicRegister') { return PublicAPI.getPoll(sessionStore.route.params.token) } if (sessionStore.route.name === 'vote') { diff --git a/src/stores/session.ts b/src/stores/session.ts index 2e7a640f78..44f5e75c0d 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -261,7 +261,7 @@ export const useSessionStore = defineStore('session', { try { const response = await (() => { - if (this.route.name === 'publicVote') { + if (this.route.name === 'publicVote' || this.route.name === 'publicRegister') { return PublicAPI.getSession(this.publicToken) } return SessionAPI.getSession() diff --git a/src/components/Public/PublicRegisterModal.vue b/src/views/PublicRegisterView.vue similarity index 52% rename from src/components/Public/PublicRegisterModal.vue rename to src/views/PublicRegisterView.vue index 796a81e79b..b02e511c0a 100644 --- a/src/components/Public/PublicRegisterModal.vue +++ b/src/views/PublicRegisterView.vue @@ -11,26 +11,27 @@ import { showError } from '@nextcloud/dialogs' import { generateUrl } from '@nextcloud/router' import { t } from '@nextcloud/l10n' -import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' +import NcAppContent from '@nextcloud/vue/components/NcAppContent' import NcButton from '@nextcloud/vue/components/NcButton' - -import InputDiv from '../Base/modules/InputDiv.vue' -import { SimpleLink } from '../../helpers/modules/SimpleLink' -import { InlineLink } from '../../helpers/modules/InlineLink' -import { setCookie } from '../../helpers/modules/cookieHelper' -import { ValidatorAPI, PublicAPI } from '../../Api' -import { useSessionStore } from '../../stores/session' -import { usePollStore } from '../../stores/poll' +import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' +import NcModal from '../components/Base/modules/CustomNcModal.vue' + +import InputDiv from '../components/Base/modules/InputDiv.vue' +import MarkDownDescription from '../components/Poll/MarkDownDescription.vue' +import PollInfoLine from '../components/Poll/PollInfoLine.vue' +import { InlineLink } from '../helpers/modules/InlineLink' +import { SimpleLink } from '../helpers/modules/SimpleLink' +import { setCookie } from '../helpers/modules/cookieHelper' +import { ValidatorAPI, PublicAPI } from '../Api' +import { useSessionStore } from '../stores/session' +import { usePollStore } from '../stores/poll' import type { AxiosError } from '@nextcloud/axios' -import type { SignalingType } from '../../Types' -import MarkDownDescription from '../Poll/MarkDownDescription.vue' +import type { SignalingType } from '../Types' const route = useRoute() const router = useRouter() -const emit = defineEmits(['close']) - const sessionStore = useSessionStore() const pollStore = usePollStore() @@ -38,6 +39,7 @@ const COOKIE_LIFETIME = 30 const sendRegistration = ref(false) const saveCookie = ref(true) +const descriptionExpanded = ref(false) const loginLink = computed(() => { const redirectUrl = router.resolve({ @@ -55,13 +57,6 @@ function updateCookie(value: string): void { setCookie(route.params.token.toString(), value, cookieExpiration) } -/** - * - */ -function closeModal(): void { - emit('close') -} - const checkStatus = ref<{ email: SignalingType userName: SignalingType @@ -171,21 +166,11 @@ const registrationIsValid = computed( ) function routeToPersonalShare(token: string): void { - if (route.params.token === token) { - // if share was not a public share, but a personal share - // (i.e. email shares allow to change personal data by fist entering of the poll), - // just refresh the session and load the poll - sessionStore.loadSession() - pollStore.load() - } else { - // in case of a public share, redirect to the generated share - router.push({ - name: 'publicVote', - params: { token }, - replace: true, - }) - } - closeModal() + router.push({ + name: 'publicVote', + params: { token }, + replace: true, + }) } async function submitRegistration(): Promise { @@ -202,7 +187,7 @@ async function submitRegistration(): Promise { emailAddress.value, ) - if (saveCookie.value && route.name === 'publicVote') { + if (saveCookie.value) { updateCookie(response.data.share.token) } @@ -237,52 +222,57 @@ const disableSubmit = computed( ) onMounted(() => { - // pre-fill input field with existing data userName.value = sessionStore.currentUser.displayName validatePublicUsername() - // pre-fill input field with existing data emailAddress.value = sessionStore.currentUser.emailAddress validateEmailAddress() }) From 7c44c62617b08c51281551b935a718bca902d776 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Fri, 3 Apr 2026 21:26:23 +0200 Subject: [PATCH 06/11] remove outcommented Signed-off-by: dartcafe --- src/App.vue | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/App.vue b/src/App.vue index 799df5b0c5..175e801eba 100644 --- a/src/App.vue +++ b/src/App.vue @@ -140,9 +140,4 @@ onUnmounted(() => { #public-page-user-menu { display: none; } - -// .app-content { -// display: flex; -// flex-direction: column; -// } From be9d3abe0d414e85c3bcc116a6f9b650b51292ee Mon Sep 17 00:00:00 2001 From: dartcafe Date: Fri, 3 Apr 2026 22:56:03 +0200 Subject: [PATCH 07/11] fix session.AppSettings Signed-off-by: dartcafe --- lib/Model/Settings/AppSettings.php | 1 + src/stores/session.ts | 47 +++++++----------------------- src/stores/session.types.ts | 14 +++++++-- 3 files changed, 24 insertions(+), 38 deletions(-) diff --git a/lib/Model/Settings/AppSettings.php b/lib/Model/Settings/AppSettings.php index cc2f9927f7..7537d8bc6f 100644 --- a/lib/Model/Settings/AppSettings.php +++ b/lib/Model/Settings/AppSettings.php @@ -121,6 +121,7 @@ private function getPublicAppSettings(): array { 'finalPrivacyUrl' => $this->getFinalPrivacyUrl(), 'finalImprintUrl' => $this->getFinalImprintUrl(), 'useLogin' => $this->getShowLogin(), + 'useSiteLegalTerms' => $this->getBooleanSetting(self::SETTING_USE_SITE_LEGAL), ]; } diff --git a/src/stores/session.ts b/src/stores/session.ts index 44f5e75c0d..9647ecdc86 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -53,42 +53,14 @@ export const useSessionStore = defineStore('session', { timezoneName: 'local', }, appSettings: { - allAccessGroups: [], - allowCombo: true, - allowPublicShares: true, - allowAllAccess: true, - allowPollCreation: true, - allowPollDownload: true, - autoArchive: false, - autoArchiveOffset: 30, - autoDelete: false, - autoDeleteOffset: 30, - defaultPrivacyUrl: '', - defaultImprintUrl: '', - disclaimer: '', - imprintUrl: '', - legalTermsInEmail: false, - privacyUrl: '', - showMailAddresses: false, - showLogin: true, - updateType: 'noPolling', - useActivity: false, - useCollaboration: true, - useSiteLegalTerms: true, - navigationPollsInList: true, - finalPrivacyUrl: '', finalImprintUrl: '', - comboGroups: [], - publicSharesGroups: [], - pollCreationGroups: [], - pollDownloadGroups: [], - showMailAddressesGroups: [], - unrestrictedOwner: false, - unrestrictedOwnerGroups: [], - groups: [], - status: { - loadingGroups: false, - }, + finalPrivacyUrl: '', + navigationPollsInList: false, + useLogin: false, + useSiteLegalTerms: true, + useActivity: false, + updateType: 'noPolling', + currentVersion: '', }, route: { currentRoute: '', @@ -261,7 +233,10 @@ export const useSessionStore = defineStore('session', { try { const response = await (() => { - if (this.route.name === 'publicVote' || this.route.name === 'publicRegister') { + if ( + this.route.name === 'publicVote' + || this.route.name === 'publicRegister' + ) { return PublicAPI.getSession(this.publicToken) } return SessionAPI.getSession() diff --git a/src/stores/session.types.ts b/src/stores/session.types.ts index 3ca81985cb..479643d93f 100644 --- a/src/stores/session.types.ts +++ b/src/stores/session.types.ts @@ -5,7 +5,6 @@ import { RouteRecordNameGeneric } from 'vue-router' -import { AppSettingsStore } from './appSettings.types' import { ViewMode } from './preferences.types' import type { Share } from './shares.types' @@ -63,9 +62,20 @@ export type AppPermissions = { unrestrictedOwner: boolean } +type AppSettings = { + finalImprintUrl: string + finalPrivacyUrl: string + navigationPollsInList: boolean + useLogin: boolean + useSiteLegalTerms: boolean + useActivity: boolean + updateType: string + currentVersion: string +} + export type Session = { appPermissions: AppPermissions - appSettings: AppSettingsStore + appSettings: AppSettings currentUser: User route: Route sessionSettings: SessionSettings From d771e686e563359399f405662f87a492728b773a Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sat, 4 Apr 2026 23:29:50 +0200 Subject: [PATCH 08/11] finalize registerView Signed-off-by: dartcafe --- lib/Model/Settings/AppSettings.php | 2 - src/App.vue | 4 + src/components/Public/PublicFooter.vue | 41 ++ .../Settings/AdminSettings/AdminLegal.vue | 7 +- src/helpers/modules/InlineLink.ts | 2 +- src/router.ts | 3 +- src/stores/options.ts | 5 +- src/stores/session.ts | 1 - src/stores/session.types.ts | 1 - src/views/PublicRegisterView.vue | 396 ++++++++++++------ 10 files changed, 317 insertions(+), 145 deletions(-) create mode 100644 src/components/Public/PublicFooter.vue diff --git a/lib/Model/Settings/AppSettings.php b/lib/Model/Settings/AppSettings.php index 7537d8bc6f..2954e22008 100644 --- a/lib/Model/Settings/AppSettings.php +++ b/lib/Model/Settings/AppSettings.php @@ -99,7 +99,6 @@ public function getAppSettings(): array { 'finalPrivacyUrl' => '', 'finalImprintUrl' => '', 'useLogin' => true, - 'useSiteLegalTerms' => true, 'useActivity' => false, 'navigationPollsInList' => false, 'updateType' => $this->getUpdateType(), @@ -121,7 +120,6 @@ private function getPublicAppSettings(): array { 'finalPrivacyUrl' => $this->getFinalPrivacyUrl(), 'finalImprintUrl' => $this->getFinalImprintUrl(), 'useLogin' => $this->getShowLogin(), - 'useSiteLegalTerms' => $this->getBooleanSetting(self::SETTING_USE_SITE_LEGAL), ]; } diff --git a/src/App.vue b/src/App.vue index 175e801eba..cefa5e32a7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -140,4 +140,8 @@ onUnmounted(() => { #public-page-user-menu { display: none; } + +#body-public a { + font-weight: 600; +} diff --git a/src/components/Public/PublicFooter.vue b/src/components/Public/PublicFooter.vue new file mode 100644 index 0000000000..2526b18621 --- /dev/null +++ b/src/components/Public/PublicFooter.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/components/Settings/AdminSettings/AdminLegal.vue b/src/components/Settings/AdminSettings/AdminLegal.vue index 4946dbf642..bd3574d19b 100644 --- a/src/components/Settings/AdminSettings/AdminLegal.vue +++ b/src/components/Settings/AdminSettings/AdminLegal.vue @@ -35,12 +35,7 @@ const placeholder = computed(() => { v-model="appSettingsStore.useSiteLegalTerms" type="switch" @update:model-value="appSettingsStore.write()"> - {{ - t( - 'polls', - 'Use the default terms for public polls and enable the default footer', - ) - }} + {{ t('polls', 'Use the default terms for public polls') }}