build: switch from yarn to npm to manage js dependencies and move js contents to root
yarn v1 is being deprecated and starts to have some issues Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
72
src/components/Settings/NotificationsOnboarding.vue
Normal file
72
src/components/Settings/NotificationsOnboarding.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div v-if="loggedUser">
|
||||
<section>
|
||||
<div class="setting-title">
|
||||
<h2>{{ $t("Participation notifications") }}</h2>
|
||||
</div>
|
||||
<div class="field">
|
||||
<strong>{{
|
||||
$t(
|
||||
"Mobilizon will send you an email when the events you are attending have important changes: date and time, address, confirmation or cancellation, etc."
|
||||
)
|
||||
}}</strong>
|
||||
<p>
|
||||
{{ $t("Other notification options:") }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<o-checkbox
|
||||
v-model="notificationOnDay"
|
||||
@input="updateSetting({ notificationOnDay })"
|
||||
>
|
||||
<strong>{{ $t("Notification on the day of the event") }}</strong>
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
"We'll use your timezone settings to send a recap of the morning of the event."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</o-checkbox>
|
||||
</div>
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
"To activate more notifications, head over to the notification settings."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// import { SnackbarProgrammatic as Snackbar } from "buefy";
|
||||
import { doUpdateSetting, useUserSettings } from "@/composition/apollo/user";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
const notificationOnDay = ref(true);
|
||||
|
||||
const { loggedUser } = useUserSettings();
|
||||
|
||||
const updateSetting = async (
|
||||
variables: Record<string, unknown>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
doUpdateSetting(variables);
|
||||
} catch (e: any) {
|
||||
// Snackbar.open({
|
||||
// message: e.message,
|
||||
// variant: "danger",
|
||||
// position: "bottom",
|
||||
// });
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
doUpdateSetting({
|
||||
notificationOnDay: true,
|
||||
notificationEachWeek: false,
|
||||
notificationBeforeEvent: false,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
60
src/components/Settings/SettingMenuItem.vue
Normal file
60
src/components/Settings/SettingMenuItem.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<li
|
||||
class="setting-menu-item"
|
||||
:class="{
|
||||
'cursor-pointer bg-mbz-yellow-alt-500 dark:bg-mbz-purple-500': isActive,
|
||||
'bg-mbz-yellow-alt-100 hover:bg-mbz-yellow-alt-200 dark:bg-mbz-purple-300 dark:hover:bg-mbz-purple-400 dark:text-white':
|
||||
!isActive,
|
||||
}"
|
||||
>
|
||||
<router-link v-if="to" :to="to">
|
||||
<span class="truncate">{{ title }}</span>
|
||||
</router-link>
|
||||
<span v-else>{{ title }}</span>
|
||||
</li>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const props = defineProps<{
|
||||
title?: string;
|
||||
to: { name: string; params?: Record<string, any> };
|
||||
}>();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const isActive = computed((): boolean => {
|
||||
if (props.to.name === route.name) {
|
||||
if (props.to.params) {
|
||||
return props.to.params.identityName === route.params.identityName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
li.setting-menu-item {
|
||||
font-size: 1.05rem;
|
||||
// background-color: #fff1de;
|
||||
margin: auto;
|
||||
|
||||
span {
|
||||
padding: 5px 15px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
cursor: pointer;
|
||||
// background-color: lighten(#fea72b, 10%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
38
src/components/Settings/SettingMenuSection.vue
Normal file
38
src/components/Settings/SettingMenuSection.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<li
|
||||
class="bg-mbz-yellow-alt-300 text-violet-2 dark:bg-mbz-purple-500 dark:text-zinc-100 text-xl"
|
||||
>
|
||||
<router-link
|
||||
class="cursor-pointer my-2 mx-0 py-2 px-3 font-medium block no-underline"
|
||||
v-if="to"
|
||||
:to="to"
|
||||
>{{ title }}</router-link
|
||||
>
|
||||
<b v-else>{{ title }}</b>
|
||||
<ul>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{
|
||||
title?: string;
|
||||
to: { name: string; params?: Record<string, any> };
|
||||
}>();
|
||||
|
||||
// const route = useRoute();
|
||||
// const slots = useSlots();
|
||||
|
||||
// const sectionActive = computed((): boolean => {
|
||||
// if (slots.default) {
|
||||
// return slots.default.some(
|
||||
// ({
|
||||
// componentOptions: {
|
||||
// propsData: { to },
|
||||
// },
|
||||
// }) => to && to.name === route.name
|
||||
// );
|
||||
// }
|
||||
// return false;
|
||||
// });
|
||||
</script>
|
||||
111
src/components/Settings/SettingsMenu.vue
Normal file
111
src/components/Settings/SettingsMenu.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<aside class="mb-6">
|
||||
<ul>
|
||||
<SettingMenuSection
|
||||
:title="t('Account')"
|
||||
:to="{ name: RouteName.ACCOUNT_SETTINGS }"
|
||||
>
|
||||
<SettingMenuItem
|
||||
:title="t('General')"
|
||||
:to="{ name: RouteName.ACCOUNT_SETTINGS_GENERAL }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Preferences')"
|
||||
:to="{ name: RouteName.PREFERENCES }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Notifications')"
|
||||
:to="{ name: RouteName.NOTIFICATIONS }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Apps')"
|
||||
:to="{ name: RouteName.AUTHORIZED_APPS }"
|
||||
/>
|
||||
</SettingMenuSection>
|
||||
<SettingMenuSection
|
||||
:title="t('Profiles')"
|
||||
:to="{ name: RouteName.IDENTITIES }"
|
||||
>
|
||||
<SettingMenuItem
|
||||
v-for="profile in identities"
|
||||
:key="profile.preferredUsername"
|
||||
:title="profile.preferredUsername"
|
||||
:to="{
|
||||
name: RouteName.UPDATE_IDENTITY,
|
||||
params: { identityName: profile.preferredUsername },
|
||||
}"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('New profile')"
|
||||
:to="{ name: RouteName.CREATE_IDENTITY }"
|
||||
/>
|
||||
</SettingMenuSection>
|
||||
<SettingMenuSection
|
||||
v-if="
|
||||
currentUser?.role &&
|
||||
[ICurrentUserRole.MODERATOR, ICurrentUserRole.ADMINISTRATOR].includes(
|
||||
currentUser?.role
|
||||
)
|
||||
"
|
||||
:title="t('Moderation')"
|
||||
:to="{ name: RouteName.MODERATION }"
|
||||
>
|
||||
<SettingMenuItem
|
||||
:title="t('Reports')"
|
||||
:to="{ name: RouteName.REPORTS }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Moderation log')"
|
||||
:to="{ name: RouteName.REPORT_LOGS }"
|
||||
/>
|
||||
<SettingMenuItem :title="t('Users')" :to="{ name: RouteName.USERS }" />
|
||||
<SettingMenuItem
|
||||
:title="t('Profiles')"
|
||||
:to="{ name: RouteName.PROFILES }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Groups')"
|
||||
:to="{ name: RouteName.ADMIN_GROUPS }"
|
||||
/>
|
||||
</SettingMenuSection>
|
||||
<SettingMenuSection
|
||||
v-if="currentUser?.role == ICurrentUserRole.ADMINISTRATOR"
|
||||
:title="t('Admin')"
|
||||
:to="{ name: RouteName.ADMIN }"
|
||||
>
|
||||
<SettingMenuItem
|
||||
:title="t('Dashboard')"
|
||||
:to="{ name: RouteName.ADMIN_DASHBOARD }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Instance settings')"
|
||||
:to="{ name: RouteName.ADMIN_SETTINGS }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Federation')"
|
||||
:to="{ name: RouteName.INSTANCES }"
|
||||
/>
|
||||
</SettingMenuSection>
|
||||
</ul>
|
||||
</aside>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ICurrentUserRole } from "@/types/enums";
|
||||
import SettingMenuSection from "./SettingMenuSection.vue";
|
||||
import SettingMenuItem from "./SettingMenuItem.vue";
|
||||
|
||||
import RouteName from "../../router/name";
|
||||
import { useCurrentUserClient } from "@/composition/apollo/user";
|
||||
import { useCurrentUserIdentities } from "@/composition/apollo/actor";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { currentUser } = useCurrentUserClient();
|
||||
const { identities } = useCurrentUserIdentities();
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(a) {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
95
src/components/Settings/SettingsOnboarding.vue
Normal file
95
src/components/Settings/SettingsOnboarding.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div v-if="loggedUser">
|
||||
<section>
|
||||
<div class="setting-title">
|
||||
<h2>{{ t("Settings") }}</h2>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{{ t("Language") }}</h3>
|
||||
<p>
|
||||
{{
|
||||
t(
|
||||
"This setting will be used to display the website and send you emails in the correct language."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<div class="has-text-centered">
|
||||
<o-select
|
||||
:loading="loading"
|
||||
v-model="locale"
|
||||
:placeholder="t('Select a language')"
|
||||
>
|
||||
<option v-for="(language, lang) in langs" :value="lang" :key="lang">
|
||||
{{ language }}
|
||||
</option>
|
||||
</o-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>{{ t("Timezone") }}</h3>
|
||||
<p>
|
||||
{{
|
||||
t(
|
||||
"We use your timezone to make sure you get notifications for an event at the correct time."
|
||||
)
|
||||
}}
|
||||
{{
|
||||
t("Your timezone was detected as {timezone}.", {
|
||||
timezone,
|
||||
})
|
||||
}}
|
||||
<o-notification
|
||||
variant="danger"
|
||||
v-if="!loading && !supportedTimezone"
|
||||
>
|
||||
{{ t("Your timezone {timezone} isn't supported.", { timezone }) }}
|
||||
</o-notification>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useTimezones } from "@/composition/apollo/config";
|
||||
import {
|
||||
doUpdateSetting,
|
||||
updateLocale,
|
||||
useUserSettings,
|
||||
} from "@/composition/apollo/user";
|
||||
import { saveLocaleData } from "@/utils/auth";
|
||||
import { computed, onMounted, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import langs from "../../i18n/langs.json";
|
||||
|
||||
const { timezones, loading } = useTimezones();
|
||||
|
||||
const { t, locale } = useI18n({ useScope: "global" });
|
||||
|
||||
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
const { loggedUser } = useUserSettings();
|
||||
|
||||
const { mutate: doUpdateLocale } = updateLocale();
|
||||
|
||||
onMounted(() => {
|
||||
doUpdateLocale({ locale: locale as unknown as string });
|
||||
doUpdateSetting({ timezone });
|
||||
});
|
||||
|
||||
watch(locale, () => {
|
||||
if (locale.value) {
|
||||
doUpdateLocale({ locale: locale as unknown as string });
|
||||
saveLocaleData(locale.value as string);
|
||||
}
|
||||
});
|
||||
|
||||
const supportedTimezone = computed((): boolean => {
|
||||
return (timezones.value ?? []).includes(timezone);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user