fix(announcements): load group announcements

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2023-11-20 12:15:19 +01:00
parent b635937091
commit 7ef85fe19b
No known key found for this signature in database
GPG key ID: A061B9DDE0CA0773
9 changed files with 124 additions and 29 deletions

View file

@ -3,13 +3,13 @@
1C29EE70E90ECED01AF28EC58D2575B5 1C29EE70E90ECED01AF28EC58D2575B5
31CE26BC979C57B9E3CC97B40C290CE5 31CE26BC979C57B9E3CC97B40C290CE5
3529E7A4CECC24D02678820E6F521162 3529E7A4CECC24D02678820E6F521162
4A4B7002DEB734A943B467DF7D2BD1AA 37E854EA3BDF7275C6A7631F80804EC4
4E7C044C59E0BCB76AA826789998F624 4E7C044C59E0BCB76AA826789998F624
53CBBEB6243FAF5C37249CBA17DE6F4C 53CBBEB6243FAF5C37249CBA17DE6F4C
5804C3D68F833A3E8D258C0704DEE775
5BCE3651A03711295046DE48BDFE007E 5BCE3651A03711295046DE48BDFE007E
5C16A2AE6A24E4795F95DDE20EEC458E
5C4CED447689F00D9D1ACEB9B895ED29
630C0972985257251EDF89A7117DE423 630C0972985257251EDF89A7117DE423
81BAE1F18B4148E83C3265F81FFA6F5C
94ACF7B17C3FF42F64E57DD1DA936BD8 94ACF7B17C3FF42F64E57DD1DA936BD8
A32E125003F1EDFAD95C487C6A969725 A32E125003F1EDFAD95C487C6A969725
ACF6272A1DBB3A2ABD96C0C120B5CA69 ACF6272A1DBB3A2ABD96C0C120B5CA69

View file

@ -29,7 +29,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Conversation do
if Actors.is_member?(actor_id, attributed_to_id) do if Actors.is_member?(actor_id, attributed_to_id) do
{:ok, {:ok,
event_id event_id
|> Conversations.find_conversations_for_event(actor_id, page, limit) |> Conversations.find_conversations_for_event(attributed_to_id, page, limit)
|> conversation_participant_to_view()} |> conversation_participant_to_view()}
else else
{:ok, %Page{total: 0, elements: []}} {:ok, %Page{total: 0, elements: []}}

View file

@ -13,16 +13,15 @@ defmodule Mobilizon.Service.Formatter.Text do
def paragraph(string, max_line_length, prefix \\ "") do def paragraph(string, max_line_length, prefix \\ "") do
string string
|> String.split("\n\n", trim: true) |> String.split("\n\n", trim: true)
|> Enum.map(&subparagraph(&1, max_line_length, prefix)) |> Enum.map_join("\n#{prefix}\n", &subparagraph(&1, max_line_length, prefix))
|> Enum.join("\n#{prefix}\n")
end end
defp subparagraph(string, max_line_length, prefix) do defp subparagraph(string, max_line_length, prefix) do
[word | rest] = String.split(string, ~r/\s+/, trim: true) [word | rest] = String.split(string, ~r/\s+/, trim: true)
lines_assemble(rest, max_line_length - String.length(prefix), String.length(word), word, []) rest
|> Enum.map(&"#{prefix}#{&1}") |> lines_assemble(max_line_length - String.length(prefix), String.length(word), word, [])
|> Enum.join("\n") |> Enum.map_join("\n", &"#{prefix}#{&1}")
end end
defp lines_assemble([], _, _, line, acc), do: [line | acc] |> Enum.reverse() defp lines_assemble([], _, _, line, acc), do: [line | acc] |> Enum.reverse()

View file

@ -0,0 +1,97 @@
<template>
<router-link
class="flex gap-4 w-full items-center px-2 py-4 border-b-stone-200 border-b bg-white dark:bg-transparent my-2 rounded"
dir="auto"
:to="{
name: RouteName.CONVERSATION,
params: { id: announcement.conversationParticipantId },
}"
>
<div class="overflow-hidden flex-1">
<div class="flex items-center justify-between">
<p>
{{
t("Sent to {count} participants", otherParticipants.length, {
count: otherParticipants.length,
})
}}
</p>
<div class="inline-flex items-center px-1.5">
<time
class="whitespace-nowrap"
:datetime="actualDate.toString()"
:title="formatDateTimeString(actualDate)"
>
{{ distanceToNow }}</time
>
</div>
</div>
<div
class="line-clamp-4 my-1"
dir="auto"
v-if="!announcement.lastComment?.deletedAt"
>
{{ htmlTextEllipsis }}
</div>
<div v-else class="">
{{ t("[This comment has been deleted]") }}
</div>
</div>
</router-link>
</template>
<script lang="ts" setup>
import { formatDistanceToNowStrict } from "date-fns";
import { IConversation } from "../../types/conversation";
import RouteName from "../../router/name";
import { computed, inject } from "vue";
import { formatDateTimeString } from "../../filters/datetime";
import type { Locale } from "date-fns";
import { useI18n } from "vue-i18n";
import { useCurrentActorClient } from "@/composition/apollo/actor";
const props = defineProps<{
announcement: IConversation;
}>();
const announcement = computed(() => props.announcement);
const dateFnsLocale = inject<Locale>("dateFnsLocale");
const { t } = useI18n({ useScope: "global" });
const distanceToNow = computed(() => {
return (
formatDistanceToNowStrict(new Date(actualDate.value), {
locale: dateFnsLocale,
}) ?? t("Right now")
);
});
const htmlTextEllipsis = computed((): string => {
const element = document.createElement("div");
if (announcement.value.lastComment && announcement.value.lastComment.text) {
element.innerHTML = announcement.value.lastComment.text
.replace(/<br\s*\/?>/gi, " ")
.replace(/<p>/gi, " ");
}
return element.innerText;
});
const actualDate = computed((): string => {
if (
announcement.value.updatedAt === announcement.value.insertedAt &&
announcement.value.lastComment?.publishedAt
) {
return announcement.value.lastComment.publishedAt;
}
return announcement.value.updatedAt;
});
const { currentActor } = useCurrentActorClient();
const otherParticipants = computed(
() =>
announcement.value?.participants.filter(
(participant) => participant.id !== currentActor.value?.id
) ?? []
);
</script>

View file

@ -2,18 +2,10 @@
<div class="container mx-auto section"> <div class="container mx-auto section">
<breadcrumbs-nav :links="[]" /> <breadcrumbs-nav :links="[]" />
<section> <section>
<h1>{{ t("Conversations") }}</h1> <h1>{{ t("Announcements") }}</h1>
<!-- <o-button
tag="router-link"
:to="{
name: RouteName.CREATE_CONVERSATION,
params: { uuid: event.uuid },
}"
>{{ t("New private message") }}</o-button
> -->
<div v-if="conversations.elements.length > 0"> <div v-if="conversations.elements.length > 0">
<conversation-list-item <announcement-list-item
:conversation="conversation" :announcement="conversation"
v-for="conversation in conversations.elements" v-for="conversation in conversations.elements"
:key="conversation.id" :key="conversation.id"
/> />
@ -30,15 +22,14 @@
> >
</o-pagination> </o-pagination>
</div> </div>
<empty-content v-else icon="chat"> <empty-content v-else icon="bullhorn" inline>
{{ t("There's no conversations yet") }} {{ t("There's no announcements yet") }}
</empty-content> </empty-content>
</section> </section>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import ConversationListItem from "../../components/Conversations/ConversationListItem.vue"; import AnnouncementListItem from "../../components/Conversations/AnnouncementListItem.vue";
// import RouteName from "../../router/name";
import EmptyContent from "../../components/Utils/EmptyContent.vue"; import EmptyContent from "../../components/Utils/EmptyContent.vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useRouteQuery, integerTransformer } from "vue-use-route-query"; import { useRouteQuery, integerTransformer } from "vue-use-route-query";

View file

@ -42,7 +42,12 @@
> >
{{ error }} {{ error }}
</o-notification> </o-notification>
<o-button class="mt-3" nativeType="submit">{{ t("Send") }}</o-button> <o-button
class="mt-3"
nativeType="submit"
:disabled="selectedRoles.length == 0"
>{{ t("Send") }}</o-button
>
</form> </form>
</template> </template>

View file

@ -1628,5 +1628,6 @@
"I've been mentionned in a conversation": "I've been mentionned in a conversation", "I've been mentionned in a conversation": "I've been mentionned in a conversation",
"New announcement": "New announcement", "New announcement": "New announcement",
"This announcement will be send to all participants with the statuses selected below. They will not be allowed to reply to your announcement, but they can create a new conversation with you.": "This announcement will be send to all participants with the statuses selected below. They will not be allowed to reply to your announcement, but they can create a new conversation with you.", "This announcement will be send to all participants with the statuses selected below. They will not be allowed to reply to your announcement, but they can create a new conversation with you.": "This announcement will be send to all participants with the statuses selected below. They will not be allowed to reply to your announcement, but they can create a new conversation with you.",
"The following participants are groups, which means group members are able to reply to this conversation:": "The following participants are groups, which means group members are able to reply to this conversation:" "The following participants are groups, which means group members are able to reply to this conversation:": "The following participants are groups, which means group members are able to reply to this conversation:",
"Sent to {count} participants": "Sent to no participants|Sent to one participant|Sent to {count} participants"
} }

View file

@ -1624,5 +1624,6 @@
"I've been mentionned in a conversation": "J'ai été mentionnée dans une conversation", "I've been mentionned in a conversation": "J'ai été mentionnée dans une conversation",
"New announcement": "Nouvelle annonce", "New announcement": "Nouvelle annonce",
"This announcement will be send to all participants with the statuses selected below. They will not be allowed to reply to your announcement, but they can create a new conversation with you.": "Cette annonce sera envoyée à tous les participant·es ayant le statut sélectionné ci-dessous. Iels ne pourront pas répondre à votre annonce, mais iels peuvent créer une nouvelle conversation avec vous.", "This announcement will be send to all participants with the statuses selected below. They will not be allowed to reply to your announcement, but they can create a new conversation with you.": "Cette annonce sera envoyée à tous les participant·es ayant le statut sélectionné ci-dessous. Iels ne pourront pas répondre à votre annonce, mais iels peuvent créer une nouvelle conversation avec vous.",
"The following participants are groups, which means group members are able to reply to this conversation:": "Les participants suivants sont des groupes, ce qui signifie que les membres du groupes peuvent répondre dans cette conversation:" "The following participants are groups, which means group members are able to reply to this conversation:": "Les participants suivants sont des groupes, ce qui signifie que les membres du groupes peuvent répondre dans cette conversation:",
} "Sent to {count} participants": "Envoyé à aucun·e participant·e|Envoyé à une participant·e|Envoyé à {count} participant·es"
}

View file

@ -138,7 +138,8 @@ defmodule Mobilizon.Service.Notifier.EmailTest do
@email "someone@somewhere.tld" @email "someone@somewhere.tld"
test "send activity notification to anonymous user" do test "send activity notification to anonymous user" do
%Activity{} = activity = insert(:mobilizon_activity, inserted_at: DateTime.utc_now()) %Activity{} =
activity = insert(:mobilizon_activity, inserted_at: DateTime.utc_now(), type: :comment)
Email.send_anonymous_activity(@email, activity, locale: "en") Email.send_anonymous_activity(@email, activity, locale: "en")