Skip to content
Merged
1 change: 1 addition & 0 deletions .github/workflows/reusable-dev-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ jobs:
--set frontend.loginInfoTextKey=${{ vars.LOGIN_INFO_TEXT_KEY }} \
--set featureToggle.developer=true \
--set featureToggle.checklist=${{ vars.FEATURE_CHECKLIST || 'false' }} \
--set featureToggle.comments=${{ vars.FEATURE_COMMENTS || 'false' }} \
--timeout ${{ vars.HELM_TIMEOUT || '5m0s' }}

- name: Finish the GitHub deployment
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/reusable-stage-prod-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ jobs:
--set autoscaling.enabled=true \
--set autoscaling.targetCPUUtilizationPercentage=90 \
--set featureToggle.checklist=${{ vars.FEATURE_CHECKLIST || 'false' }} \
--set featureToggle.comments=${{ vars.FEATURE_COMMENTS || 'false' }} \
--timeout ${{ vars.HELM_TIMEOUT || '5m0s' }}

- name: Finish the GitHub deployment
Expand Down
1 change: 1 addition & 0 deletions .helm/ecamp3/templates/frontend_configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ data:
{{- end }}
FEATURE_DEVELOPER: {{ .Values.featureToggle.developer | default false }},
FEATURE_CHECKLIST: {{ .Values.featureToggle.checklist | default false }},
FEATURE_COMMENTS: {{ .Values.featureToggle.comments | default false }},
LOGIN_INFO_TEXT_KEY: '{{ .Values.frontend.loginInfoTextKey }}',
}
deployedVersion: {{ .Values.deployedVersion | quote }}
86 changes: 86 additions & 0 deletions frontend/src/components/comments/Comment.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<template>
<v-sheet
outlined
class="ec-comment"
elevation="2"
rounded="lg"
border="left"
colored-border="blue"
>
<v-card-text class="px-3 pt-2 pb-2 ec-comment__text">
<slot />
</v-card-text>
<PromptEntityDelete
v-if="isDeletable()"
:entity="comment._meta.self"
class="ec-comment__delete"
warning-text-entity="Kommentar"
>
<template #activator="{ attrs, on }">
<v-btn
v-if="isDeletable()"
class="ec-comment__delete"
icon
absolute
right
v-bind="attrs"
v-on="on"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</template>
</PromptEntityDelete>
</v-sheet>
</template>

<script>
import PromptEntityDelete from '@/components/prompt/PromptEntityDelete.vue'
import { mapGetters } from 'vuex'

export default {
name: 'Comment',
components: { PromptEntityDelete },
props: {
comment: {
type: Object,
required: false,
},
},

methods: {
isDeletable() {
return this.comment !== undefined && this.comment.author().id === this.authUser.id
},
},
computed: {
...mapGetters({
authUser: 'getLoggedInUser',
}),
},
}
</script>

<style scoped>
.ec-comment {
background-color: #cfe2f1 !important;
border-color: #e3edfc #cfe2f1 #588ebc !important;
position: relative;
}

.ec-comment:not(:hover) .ec-comment__delete {
display: none;
}

.ec-comment button.ec-comment__delete {
top: 0;
right: 0rem;
}

.ec-comment__text :deep(p) {
margin-bottom: 6px;
font-size: 0.875rem;
font-weight: 400;
line-height: 1.375rem;
letter-spacing: -0.006em;
}
</style>
56 changes: 56 additions & 0 deletions frontend/src/components/comments/CommentWrapper.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<template>
<div style="display: flex" class="gap-4">
<div style="flex-grow: 1; flex-shrink: 1">
<slot />
</div>
<template v-if="openComments">
<div
v-if="$vuetify.breakpoint.width > 1360"
style="flex-basis: 320px"
class="d-flex flex-column gap-2 items-center"
>
<slot name="comments" />
</div>
<v-navigation-drawer
v-else
v-model="openComments"
clipped
right
app
permanent
temporary
color="blue-grey"
floating
width="320"
>
<div class="py-3 px-3 d-flex flex-column gap-2 items-center">
<slot name="comments" />
</div>
</v-navigation-drawer>
</template>
<v-btn
fab
fixed
bottom
right
color="primary"
class="mb-4 mr-4"
@click="openComments = !openComments"
>
<v-icon>mdi-chat</v-icon>
</v-btn>
</div>
</template>

<script>
export default {
name: 'CommentWrapper',
data() {
return {
openComments: false,
}
},
}
</script>

<style scoped></style>
1 change: 1 addition & 0 deletions frontend/src/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function getEnv() {
HELP_LINK: env.HELP_LINK ?? 'https://ecamp3.ch/faq',
FEATURE_DEVELOPER: (env.VITE_FEATURE_DEVELOPER ?? 'true') === 'true',
FEATURE_CHECKLIST: (env.VITE_FEATURE_CHECKLIST ?? 'true') === 'true',
FEATURE_COMMENTS: (env.VITE_FEATURE_COMMENTS ?? 'true') === 'true',
LOGIN_INFO_TEXT_KEY: env.VITE_LOGIN_INFO_TEXT_KEY ?? 'dev',
}
}
113 changes: 111 additions & 2 deletions frontend/src/views/camp/activity/Activity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,81 @@ Displays a single activity

<template>
<v-container fluid>
<ScheduleEntry :activity-id="activityId" :schedule-entry-id="scheduleEntryId" />
<ScheduleEntry
v-if="!featureCommentsEnabled"
:activity-id="activityId"
:schedule-entry-id="scheduleEntryId"
/>
<CommentWrapper v-else-if="!comments._meta.loading">
<ScheduleEntry :activity-id="activityId" :schedule-entry-id="scheduleEntryId" />
<template #comments>
<Comment
v-for="comment in comments.items"
:key="comment._meta.self"
deletable
:comment="comment"
>
<e-richtext
class="e-story-day e-story-day-readonly"
:value="comment.textHtml"
:readonly="true"
:outlined="false"
:solo="false"
auto-grow
dense
label=""
/>
<div class="d-flex align-center justify-space-between mt-1 gap-2">
<span
><UserAvatar :user="comment.author()" size="24" class="mr-1" />
{{ comment.author().displayName }}</span
>
<span>{{
$date(comment.createTime).format($tc('global.datetime.dateTimeLong'))
}}</span>
</div>
</Comment>
<Comment class="relative">
<e-richtext
class="e-story-day e-story-day--textmode"
:value="newComment"
placeholder="Kommentar"
@input="onInput"
/>
<div class="d-flex align-center mt-2 gap-2">
<span
><UserAvatar :user="authUser" size="24" class="mr-1" />
{{ authUser.displayName }}</span
>
</div>
<v-btn
absolute
text
style="bottom: 2px; right: 1px"
:disabled="newComment.length === 0"
@click="addComment"
>Send</v-btn
>
</Comment>
</template>
</CommentWrapper>
</v-container>
</template>

<script>
import ScheduleEntry from '@/components/activity/ScheduleEntry.vue'
import CommentWrapper from '@/components/comments/CommentWrapper.vue'
import UserAvatar from '@/components/user/UserAvatar.vue'
import { getEnv } from '@/environment.js'
import { mapGetters } from 'vuex'

export default {
name: 'Activity',
components: {
UserAvatar,
CommentWrapper,
ScheduleEntry,
},

props: {
activityId: {
type: String,
Expand All @@ -27,5 +89,52 @@ export default {
default: null,
},
},
data() {
return {
newComment: '',
}
},
computed: {
...mapGetters({
authUser: 'getLoggedInUser',
}),
comments() {
return this.api.get().activities({ id: this.activityId }).comments()
},
featureCommentsEnabled() {
return getEnv().FEATURE_COMMENTS ?? false
},
},
methods: {
onInput(newValue) {
this.newComment = newValue
},
async addComment() {
const activity = this.api.get().activities({ id: this.activityId })
await this.api.post(await this.api.href(this.api.get(), 'comments'), {
textHtml: this.newComment,
activity: activity._meta.self,
camp: activity.camp()._meta.self,
})
await this.comments.$reload()
this.newComment = ''
},
},
}
</script>

<style scoped>
.e-story-day :deep(.v-text-field) {
margin-top: 0;
padding-top: 0;
}

.e-story-day.e-story-day-readonly :deep(.v-input__slot) {
padding: 0 !important;
}

/* this disables the bottom border which is displayed for VTextField in "regular" style */
.e-story-day--textmode :deep(.v-input__slot)::before {
display: none;
}
</style>
Loading