Introduce group basic federation, event new page and notifications
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import { IActor } from '@/types/actor';
|
||||
import { IEvent } from '@/types/event.model';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { IActor } from "@/types/actor";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class ActorMixin extends Vue {
|
||||
actorIsOrganizer(actor: IActor, event: IEvent) {
|
||||
console.log('actorIsOrganizer actor', actor.id);
|
||||
console.log('actorIsOrganizer event', event);
|
||||
static actorIsOrganizer(actor: IActor, event: IEvent) {
|
||||
console.log("actorIsOrganizer actor", actor.id);
|
||||
console.log("actorIsOrganizer event", event);
|
||||
return event.organizerActor && actor.id === event.organizerActor.id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
import { mixins } from 'vue-class-component';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { IEvent, IParticipant, ParticipantRole } from '@/types/event.model';
|
||||
import { DELETE_EVENT, EVENT_PERSON_PARTICIPATION, FETCH_EVENT, LEAVE_EVENT } from '@/graphql/event';
|
||||
import { RouteName } from '@/router';
|
||||
import { IActor, IPerson } from '@/types/actor';
|
||||
import { mixins } from "vue-class-component";
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import { IEvent, IParticipant, ParticipantRole } from "../types/event.model";
|
||||
import {
|
||||
DELETE_EVENT,
|
||||
EVENT_PERSON_PARTICIPATION,
|
||||
FETCH_EVENT,
|
||||
LEAVE_EVENT,
|
||||
} from "../graphql/event";
|
||||
import RouteName from "../router/name";
|
||||
import { IPerson } from "../types/actor";
|
||||
|
||||
@Component
|
||||
export default class EventMixin extends mixins(Vue) {
|
||||
|
||||
protected async leaveEvent(
|
||||
event: IEvent,
|
||||
actorId: number,
|
||||
token: String|null = null,
|
||||
anonymousParticipationConfirmed: boolean|null = null,
|
||||
event: IEvent,
|
||||
actorId: string,
|
||||
token: string | null = null,
|
||||
anonymousParticipationConfirmed: boolean | null = null
|
||||
) {
|
||||
try {
|
||||
const { data } = await this.$apollo.mutate<{ leaveEvent: IParticipant }>({
|
||||
const { data: resultData } = await this.$apollo.mutate<{ leaveEvent: IParticipant }>({
|
||||
mutation: LEAVE_EVENT,
|
||||
variables: {
|
||||
eventId: event.id,
|
||||
@@ -34,10 +38,10 @@ export default class EventMixin extends mixins(Vue) {
|
||||
if (participationCachedData == null) return;
|
||||
const { person } = participationCachedData;
|
||||
if (person === null) {
|
||||
console.error('Cannot update participation cache, because of null value.');
|
||||
console.error("Cannot update participation cache, because of null value.");
|
||||
return;
|
||||
}
|
||||
participation = person.participations[0];
|
||||
[participation] = person.participations;
|
||||
person.participations = [];
|
||||
store.writeQuery({
|
||||
query: EVENT_PERSON_PARTICIPATION,
|
||||
@@ -46,25 +50,32 @@ export default class EventMixin extends mixins(Vue) {
|
||||
});
|
||||
}
|
||||
|
||||
const eventCachedData = store.readQuery<{ event: IEvent }>({ query: FETCH_EVENT, variables: { uuid: event.uuid } });
|
||||
const eventCachedData = store.readQuery<{ event: IEvent }>({
|
||||
query: FETCH_EVENT,
|
||||
variables: { uuid: event.uuid },
|
||||
});
|
||||
if (eventCachedData == null) return;
|
||||
const { event: eventCached } = eventCachedData;
|
||||
if (eventCached === null) {
|
||||
console.error('Cannot update event cache, because of null value.');
|
||||
console.error("Cannot update event cache, because of null value.");
|
||||
return;
|
||||
}
|
||||
if (participation && participation.role === ParticipantRole.NOT_APPROVED) {
|
||||
eventCached.participantStats.notApproved = eventCached.participantStats.notApproved - 1;
|
||||
eventCached.participantStats.notApproved -= 1;
|
||||
} else if (anonymousParticipationConfirmed === false) {
|
||||
eventCached.participantStats.notConfirmed = eventCached.participantStats.notApproved - 1;
|
||||
eventCached.participantStats.notConfirmed -= 1;
|
||||
} else {
|
||||
eventCached.participantStats.going = eventCached.participantStats.going - 1;
|
||||
eventCached.participantStats.participant = eventCached.participantStats.participant - 1;
|
||||
eventCached.participantStats.going -= 1;
|
||||
eventCached.participantStats.participant -= 1;
|
||||
}
|
||||
store.writeQuery({ query: FETCH_EVENT, variables: { uuid: event.uuid }, data: { event: eventCached } });
|
||||
store.writeQuery({
|
||||
query: FETCH_EVENT,
|
||||
variables: { uuid: event.uuid },
|
||||
data: { event: eventCached },
|
||||
});
|
||||
},
|
||||
});
|
||||
if (data) {
|
||||
if (resultData) {
|
||||
this.participationCancelledMessage();
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -73,31 +84,30 @@ export default class EventMixin extends mixins(Vue) {
|
||||
}
|
||||
|
||||
private participationCancelledMessage() {
|
||||
this.$notifier.success(this.$t('You have cancelled your participation') as string);
|
||||
this.$notifier.success(this.$t("You have cancelled your participation") as string);
|
||||
}
|
||||
|
||||
protected async openDeleteEventModal(event: IEvent, currentActor: IPerson) {
|
||||
function escapeRegExp(string) {
|
||||
function escapeRegExp(string: string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
}
|
||||
const participantsLength = event.participantStats.participant;
|
||||
const prefix = participantsLength
|
||||
? this.$tc('There are {participants} participants.', event.participantStats.participant, {
|
||||
participants: event.participantStats.participant,
|
||||
})
|
||||
: '';
|
||||
? this.$tc("There are {participants} participants.", event.participantStats.participant, {
|
||||
participants: event.participantStats.participant,
|
||||
})
|
||||
: "";
|
||||
|
||||
this.$buefy.dialog.prompt({
|
||||
type: 'is-danger',
|
||||
title: this.$t('Delete event') as string,
|
||||
type: "is-danger",
|
||||
title: this.$t("Delete event") as string,
|
||||
message: `${prefix}
|
||||
${this.$t('Are you sure you want to delete this event? This action cannot be reverted.')}
|
||||
${this.$t("Are you sure you want to delete this event? This action cannot be reverted.")}
|
||||
<br><br>
|
||||
${this.$t('To confirm, type your event title "{eventTitle}"', { eventTitle: event.title })}`,
|
||||
confirmText: this.$t(
|
||||
'Delete {eventTitle}',
|
||||
{ eventTitle: event.title },
|
||||
) as string,
|
||||
${this.$t('To confirm, type your event title "{eventTitle}"', {
|
||||
eventTitle: event.title,
|
||||
})}`,
|
||||
confirmText: this.$t("Delete {eventTitle}", { eventTitle: event.title }) as string,
|
||||
inputAttrs: {
|
||||
placeholder: event.title,
|
||||
pattern: escapeRegExp(event.title),
|
||||
@@ -118,16 +128,17 @@ export default class EventMixin extends mixins(Vue) {
|
||||
},
|
||||
});
|
||||
/**
|
||||
* When the event corresponding has been deleted (by the organizer). A notification is already triggered.
|
||||
* When the event corresponding has been deleted (by the organizer).
|
||||
* A notification is already triggered.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.$emit('eventDeleted', event.id);
|
||||
this.$emit("eventDeleted", event.id);
|
||||
|
||||
this.$buefy.notification.open({
|
||||
message: this.$t('Event {eventTitle} deleted', { eventTitle }) as string,
|
||||
type: 'is-success',
|
||||
position: 'is-bottom-right',
|
||||
message: this.$t("Event {eventTitle} deleted", { eventTitle }) as string,
|
||||
type: "is-success",
|
||||
position: "is-bottom-right",
|
||||
duration: 5000,
|
||||
});
|
||||
await this.$router.push({ name: RouteName.HOME });
|
||||
@@ -135,4 +146,12 @@ export default class EventMixin extends mixins(Vue) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
urlToHostname(url: string): string | null {
|
||||
try {
|
||||
return new URL(url).hostname;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Component, Mixins, Vue } from 'vue-property-decorator';
|
||||
import { Person } from '@/types/actor';
|
||||
import { Component, Mixins, Vue } from "vue-property-decorator";
|
||||
import { Person } from "@/types/actor";
|
||||
|
||||
@Component({})
|
||||
export default class IdentityEditionMixin extends Mixins(Vue) {
|
||||
|
||||
identity: Person = new Person();
|
||||
|
||||
oldDisplayName: string | null = null;
|
||||
|
||||
autoUpdateUsername(newDisplayName: string | null) {
|
||||
@@ -18,18 +18,21 @@ export default class IdentityEditionMixin extends Mixins(Vue) {
|
||||
}
|
||||
|
||||
private static convertToUsername(value: string | null) {
|
||||
if (!value) return '';
|
||||
if (!value) return "";
|
||||
|
||||
// https://stackoverflow.com/a/37511463
|
||||
return value.toLocaleLowerCase()
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/ /g, '_')
|
||||
.replace(/[^a-z0-9_]/g, '')
|
||||
;
|
||||
// https://stackoverflow.com/a/37511463
|
||||
return value
|
||||
.toLocaleLowerCase()
|
||||
.normalize("NFD")
|
||||
.replace(/[\u0300-\u036f]/g, "")
|
||||
.replace(/ /g, "_")
|
||||
.replace(/[^a-z0-9_]/g, "");
|
||||
}
|
||||
|
||||
validateUsername() {
|
||||
return this.identity.preferredUsername === IdentityEditionMixin.convertToUsername(this.identity.preferredUsername);
|
||||
return (
|
||||
this.identity.preferredUsername ===
|
||||
IdentityEditionMixin.convertToUsername(this.identity.preferredUsername)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { Refs } from '@/shims-vue';
|
||||
import { ActorType, IActor } from '@/types/actor';
|
||||
import { IFollower } from '@/types/actor/follower.model';
|
||||
import { Component, Vue, Ref } from "vue-property-decorator";
|
||||
import { ActorType, IActor } from "@/types/actor";
|
||||
import { IFollower } from "@/types/actor/follower.model";
|
||||
|
||||
@Component
|
||||
export default class RelayMixin extends Vue {
|
||||
$refs!: Refs<{
|
||||
table: any,
|
||||
}>;
|
||||
@Ref("table") readonly table!: any;
|
||||
|
||||
checkedRows: IFollower[] = [];
|
||||
page: number = 1;
|
||||
perPage: number = 10;
|
||||
|
||||
toggle(row) {
|
||||
this.$refs.table.toggleDetails(row);
|
||||
page = 1;
|
||||
|
||||
perPage = 10;
|
||||
|
||||
toggle(row: object) {
|
||||
this.table.toggleDetails(row);
|
||||
}
|
||||
|
||||
async onPageChange(page: number) {
|
||||
@@ -38,7 +37,10 @@ export default class RelayMixin extends Vue {
|
||||
});
|
||||
}
|
||||
|
||||
isInstance(actor: IActor): boolean {
|
||||
return actor.type === ActorType.APPLICATION && (actor.preferredUsername === 'relay' || actor.preferredUsername === actor.domain);
|
||||
static isInstance(actor: IActor): boolean {
|
||||
return (
|
||||
actor.type === ActorType.APPLICATION &&
|
||||
(actor.preferredUsername === "relay" || actor.preferredUsername === actor.domain)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
17
js/src/mixins/resource.ts
Normal file
17
js/src/mixins/resource.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import { IResource } from "@/types/resource";
|
||||
|
||||
@Component
|
||||
export default class ResourceMixin extends Vue {
|
||||
static resourcePath(resource: IResource): string {
|
||||
const { path } = resource;
|
||||
if (path && path[0] === "/") {
|
||||
return path.slice(1);
|
||||
}
|
||||
return path || "";
|
||||
}
|
||||
|
||||
static resourcePathArray(resource: IResource): string[] {
|
||||
return ResourceMixin.resourcePath(resource).split("/");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user