Migrate to Vue 3 and Vite

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2022-07-12 10:55:28 +02:00
parent 8f4099ee33
commit ee20e03cc2
464 changed files with 31515 additions and 32758 deletions

View File

@@ -9,12 +9,11 @@ import {
} from "@/constants";
import { ILogin, IToken } from "@/types/login.model";
import { UPDATE_CURRENT_USER_CLIENT } from "@/graphql/user";
import { ApolloClient } from "@apollo/client/core/ApolloClient";
import { IPerson } from "@/types/actor";
import { IDENTITIES, UPDATE_CURRENT_ACTOR_CLIENT } from "@/graphql/actor";
import { UPDATE_CURRENT_ACTOR_CLIENT } from "@/graphql/actor";
import { ICurrentUserRole } from "@/types/enums";
import { NormalizedCacheObject } from "@apollo/client/cache/inmemory/types";
import { LOGOUT } from "@/graphql/auth";
import { provideApolloClient, useMutation } from "@vue/apollo-composable";
import { apolloClient } from "@/vue-apollo";
export function saveTokenData(obj: IToken): void {
localStorage.setItem(AUTH_ACCESS_TOKEN, obj.accessToken);
@@ -37,10 +36,6 @@ export function getLocaleData(): string | null {
return localStorage ? localStorage.getItem(USER_LOCALE) : null;
}
export function saveActorData(obj: IPerson): void {
localStorage.setItem(AUTH_USER_ACTOR_ID, `${obj.id}`);
}
export function deleteUserData(): void {
[
AUTH_USER_ID,
@@ -54,78 +49,35 @@ export function deleteUserData(): void {
});
}
export class NoIdentitiesException extends Error {}
export async function logout(performServerLogout = true): Promise<void> {
const { mutate: logout } = provideApolloClient(apolloClient)(() =>
useMutation(LOGOUT)
);
const { mutate: cleanUserClient } = provideApolloClient(apolloClient)(() =>
useMutation(UPDATE_CURRENT_USER_CLIENT)
);
const { mutate: cleanActorClient } = provideApolloClient(apolloClient)(() =>
useMutation(UPDATE_CURRENT_ACTOR_CLIENT)
);
export async function changeIdentity(
apollo: ApolloClient<NormalizedCacheObject>,
identity: IPerson
): Promise<void> {
await apollo.mutate({
mutation: UPDATE_CURRENT_ACTOR_CLIENT,
variables: identity,
});
saveActorData(identity);
}
/**
* We fetch from localStorage the latest actor ID used,
* then fetch the current identities to set in cache
* the current identity used
*/
export async function initializeCurrentActor(
apollo: ApolloClient<any>
): Promise<void> {
const actorId = localStorage.getItem(AUTH_USER_ACTOR_ID);
const result = await apollo.query({
query: IDENTITIES,
fetchPolicy: "network-only",
});
const { identities } = result.data;
if (identities.length < 1) {
console.warn("Logged user has no identities!");
throw new NoIdentitiesException();
}
const activeIdentity =
identities.find((identity: IPerson) => identity.id === actorId) ||
(identities[0] as IPerson);
if (activeIdentity) {
await changeIdentity(apollo, activeIdentity);
}
}
export async function logout(
apollo: ApolloClient<NormalizedCacheObject>,
performServerLogout = true
): Promise<void> {
if (performServerLogout) {
await apollo.mutate({
mutation: LOGOUT,
variables: {
refreshToken: localStorage.getItem(AUTH_REFRESH_TOKEN),
},
logout({
refreshToken: localStorage.getItem(AUTH_REFRESH_TOKEN),
});
}
await apollo.mutate({
mutation: UPDATE_CURRENT_USER_CLIENT,
variables: {
id: null,
email: null,
isLoggedIn: false,
role: ICurrentUserRole.USER,
},
cleanUserClient({
id: null,
email: null,
isLoggedIn: false,
role: ICurrentUserRole.USER,
});
await apollo.mutate({
mutation: UPDATE_CURRENT_ACTOR_CLIENT,
variables: {
id: null,
avatar: null,
preferredUsername: null,
name: null,
},
cleanActorClient({
id: null,
avatar: null,
preferredUsername: null,
name: null,
});
deleteUserData();

28
js/src/utils/graphics.ts Normal file
View File

@@ -0,0 +1,28 @@
import random from "lodash/random";
export const randomGradient = (): string => {
const direction = [
"bg-gradient-to-t",
"bg-gradient-to-tr",
"bg-gradient-to-r",
"bg-gradient-to-br",
"bg-gradient-to-b",
"bg-gradient-to-bl",
"bg-gradient-to-l",
"bg-gradient-to-tl",
];
const gradients = [
"from-pink-500 via-red-500 to-yellow-500",
"from-green-400 via-blue-500 to-purple-600",
"from-pink-400 via-purple-300 to-indigo-400",
"from-yellow-300 via-yellow-500 to-yellow-700",
"from-yellow-300 via-green-400 to-green-500",
"from-red-400 via-red-600 to-yellow-400",
"from-green-400 via-green-500 to-blue-700",
"from-yellow-400 via-yellow-500 to-yellow-700",
"from-green-300 via-green-400 to-purple-700",
];
return `${direction[random(0, direction.length - 1)]} ${
gradients[random(0, gradients.length - 1)]
}`;
};

View File

@@ -1,10 +1,9 @@
import Vue from "vue";
import VueI18n from "vue-i18n";
import { DateFnsPlugin } from "@/plugins/dateFns";
import { createI18n } from "vue-i18n";
import en from "../i18n/en_US.json";
import langs from "../i18n/langs.json";
import { getLocaleData } from "./auth";
import pluralizationRules from "../i18n/pluralRules";
// import messages from "@intlify/vite-plugin-vue-i18n/messages";
const DEFAULT_LOCALE = "en_US";
@@ -39,17 +38,18 @@ export const locale =
console.debug("chosen locale", locale);
Vue.use(VueI18n);
export const i18n = new VueI18n({
locale: DEFAULT_LOCALE, // set locale
export const i18n = createI18n({
legacy: false,
locale: locale, // set locale
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// messages, // set locale messages
messages: en, // set locale messages
fallbackLocale: DEFAULT_LOCALE,
formatFallbackMessages: true,
pluralizationRules,
fallbackRootWithEmptyString: true,
globalInjection: true,
});
console.debug("set VueI18n with default locale", DEFAULT_LOCALE);
@@ -58,7 +58,7 @@ const loadedLanguages = [DEFAULT_LOCALE];
function setI18nLanguage(lang: string): string {
console.debug("setting i18n locale to", lang);
i18n.locale = lang;
i18n.global.locale = lang;
setLanguageInDOM(lang);
return lang;
}
@@ -93,19 +93,9 @@ function vueI18NfileForLanguage(lang: string) {
return fileForLanguage(matches, lang);
}
function dateFnsfileForLanguage(lang: string) {
const matches: Record<string, string> = {
en_US: "en-US",
en: "en-US",
};
return fileForLanguage(matches, lang);
}
Vue.use(DateFnsPlugin, { locale: dateFnsfileForLanguage(locale) });
export async function loadLanguageAsync(lang: string): Promise<string> {
// If the same language
if (i18n.locale === lang) {
if (i18n.global.locale === lang) {
console.debug("already using language", lang);
return Promise.resolve(setI18nLanguage(lang));
}
@@ -118,11 +108,9 @@ export async function loadLanguageAsync(lang: string): Promise<string> {
// If the language hasn't been loaded yet
console.debug("loading language", lang);
const newMessages = await import(
/* webpackChunkName: "lang-[request]" */ `@/i18n/${vueI18NfileForLanguage(
lang
)}.json`
`../i18n/${vueI18NfileForLanguage(lang)}.json`
);
i18n.setLocaleMessage(lang, newMessages.default);
i18n.global.setLocaleMessage(lang, newMessages.default);
loadedLanguages.push(lang);
return setI18nLanguage(lang);
}

69
js/src/utils/identity.ts Normal file
View File

@@ -0,0 +1,69 @@
import { AUTH_USER_ACTOR_ID } from "@/constants";
import { UPDATE_CURRENT_ACTOR_CLIENT, IDENTITIES } from "@/graphql/actor";
import { IPerson } from "@/types/actor";
import { apolloClient } from "@/vue-apollo";
import {
provideApolloClient,
useMutation,
useQuery,
} from "@vue/apollo-composable";
import { computed, watch } from "vue";
export class NoIdentitiesException extends Error {}
export function saveActorData(obj: IPerson): void {
localStorage.setItem(AUTH_USER_ACTOR_ID, `${obj.id}`);
}
export async function changeIdentity(identity: IPerson): Promise<void> {
console.debug("Changing identity to", identity);
if (!identity.id) return;
const { mutate: updateCurrentActorClient } = provideApolloClient(
apolloClient
)(() => useMutation(UPDATE_CURRENT_ACTOR_CLIENT));
updateCurrentActorClient(identity);
if (identity.id) {
saveActorData(identity);
}
}
/**
* We fetch from localStorage the latest actor ID used,
* then fetch the current identities to set in cache
* the current identity used
*/
export async function initializeCurrentActor(): Promise<void> {
const actorId = localStorage.getItem(AUTH_USER_ACTOR_ID);
console.debug(
"initializing current actor, using actorId from localstorage",
actorId
);
const { result: identitiesResult } = provideApolloClient(apolloClient)(() =>
useQuery<{ identities: IPerson[] }>(IDENTITIES)
);
console.debug("identitiesResult", identitiesResult);
const identities = computed(() => identitiesResult.value?.identities);
watch(identities, async () => {
console.debug("identities found", identities.value);
if (identities.value && identities.value.length < 1) {
console.warn("Logged user has no identities!");
throw new NoIdentitiesException();
}
const activeIdentity =
(identities.value || []).find(
(identity: IPerson | undefined) => identity?.id === actorId
) || ((identities.value || [])[0] as IPerson);
console.debug("active identity is", activeIdentity);
if (activeIdentity) {
console.debug("active identity found, setting it up");
await changeIdentity(activeIdentity);
}
});
}

22
js/src/utils/location.ts Normal file
View File

@@ -0,0 +1,22 @@
import ngeohash from "ngeohash";
const GEOHASH_DEPTH = 9; // put enough accuracy, radius will be used anyway
export const coordsToGeoHash = (
lat: number | undefined,
lon: number | undefined,
depth = GEOHASH_DEPTH
): string | undefined => {
if (lat && lon && depth) {
return ngeohash.encode(lat, lon, GEOHASH_DEPTH);
}
return undefined;
};
export const geoHashToCoords = (
geohash: string | undefined
): { latitude: number; longitude: number } | undefined => {
if (!geohash) return undefined;
const { latitude, longitude } = ngeohash.decode(geohash);
return latitude && longitude ? { latitude, longitude } : undefined;
};

80
js/src/utils/share.ts Normal file
View File

@@ -0,0 +1,80 @@
export const twitterShareUrl = (
url: string | undefined,
text: string | undefined
): string | undefined => {
if (!url || !text) return undefined;
return `https://twitter.com/intent/tweet?url=${encodeURIComponent(
url
)}&text=${text}`;
};
export const facebookShareUrl = (
url: string | undefined
): string | undefined => {
if (!url) return undefined;
return `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
url
)}`;
};
export const linkedInShareUrl = (
url: string | undefined,
text: string | undefined
): string | undefined => {
if (!url || !text) return undefined;
return `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(
url
)}&title=${text}`;
};
export const whatsAppShareUrl = (
url: string | undefined,
text: string | undefined
): string | undefined => {
if (!url || !text) return undefined;
return `https://wa.me/?text=${encodeURIComponent(
basicTextToEncode(url, text)
)}`;
};
export const telegramShareUrl = (
url: string | undefined,
text: string | undefined
): string | undefined => {
if (!url || !text) return undefined;
return `https://t.me/share/url?url=${encodeURIComponent(
url
)}&text=${encodeURIComponent(text)}`;
};
export const emailShareUrl = (
url: string | undefined,
text: string | undefined
): string | undefined => {
if (!url || !text) return undefined;
return `mailto:?to=&body=${url}&subject=${text}`;
};
export const diasporaShareUrl = (
url: string | undefined,
text: string | undefined
): string | undefined => {
if (!url || !text) return undefined;
return `https://share.diasporafoundation.org/?title=${encodeURIComponent(
text
)}&url=${encodeURIComponent(url)}`;
};
export const mastodonShareUrl = (
url: string | undefined,
text: string | undefined
): string | undefined => {
if (!url || !text) return undefined;
return `https://toot.kytta.dev/?text=${encodeURIComponent(
basicTextToEncode(url, text)
)}`;
};
const basicTextToEncode = (url: string, text: string): string => {
return `${text}\r\n${url}`;
};