123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- <script setup lang="ts">
- import Toast from "toasters";
- import { storeToRefs } from "pinia";
- import { onBeforeUnmount, onMounted, watch } from "vue";
- import validation from "@/validation";
- import { useWebsocketsStore } from "@/stores/websockets";
- import { useUserAuthStore } from "@/stores/userAuth";
- import { useEditPlaylistStore } from "@/stores/editPlaylist";
- import { useModalsStore } from "@/stores/modals";
- import { useForm } from "@/composables/useForm";
- const props = defineProps({
- modalUuid: { type: String, required: true }
- });
- const userAuthStore = useUserAuthStore();
- const { loggedIn, userId } = storeToRefs(userAuthStore);
- const { hasPermission } = userAuthStore;
- const { socket } = useWebsocketsStore();
- const editPlaylistStore = useEditPlaylistStore(props);
- const { playlist } = storeToRefs(editPlaylistStore);
- const { preventCloseUnsaved } = useModalsStore();
- const isOwner = () =>
- loggedIn.value && userId.value === playlist.value.createdBy;
- const isEditable = permission =>
- ((playlist.value.type === "user" ||
- playlist.value.type === "user-liked" ||
- playlist.value.type === "user-disliked") &&
- (isOwner() || hasPermission(permission))) ||
- (playlist.value.type === "genre" &&
- permission === "playlists.update.privacy" &&
- hasPermission(permission));
- const {
- inputs: displayNameInputs,
- unsavedChanges: displayNameUnsaved,
- save: saveDisplayName,
- setOriginalValue: setDisplayName
- } = useForm(
- {
- displayName: {
- value: playlist.value.displayName,
- validate: value => {
- if (!validation.isLength(value, 2, 32)) {
- const err =
- "Display name must have between 2 and 32 characters.";
- new Toast(err);
- return err;
- }
- if (!validation.regex.ascii.test(value)) {
- const err =
- "Invalid display name format. Only ASCII characters are allowed.";
- new Toast(err);
- return err;
- }
- return true;
- }
- }
- },
- (status, message, values) =>
- new Promise((resolve, reject) => {
- if (status === "success")
- socket.dispatch(
- "playlists.updateDisplayName",
- playlist.value._id,
- values.displayName,
- res => {
- playlist.value.displayName = values.displayName;
- if (res.status === "success") {
- resolve();
- new Toast(res.message);
- } else reject(new Error(res.message));
- }
- );
- else new Toast(message);
- }),
- {
- modalUuid: props.modalUuid,
- preventCloseUnsaved: false
- }
- );
- const {
- inputs: privacyInputs,
- unsavedChanges: privacyUnsaved,
- save: savePrivacy,
- setOriginalValue: setPrivacy
- } = useForm(
- { privacy: playlist.value.privacy },
- (status, message, values) =>
- new Promise((resolve, reject) => {
- if (status === "success")
- socket.dispatch(
- playlist.value.type === "genre"
- ? "playlists.updatePrivacyAdmin"
- : "playlists.updatePrivacy",
- playlist.value._id,
- values.privacy,
- res => {
- playlist.value.privacy = values.privacy;
- if (res.status === "success") {
- resolve();
- new Toast(res.message);
- } else reject(new Error(res.message));
- }
- );
- else new Toast(message);
- }),
- {
- modalUuid: props.modalUuid,
- preventCloseUnsaved: false
- }
- );
- watch(playlist, (value, oldValue) => {
- if (value.displayName !== oldValue.displayName)
- setDisplayName({ displayName: value.displayName });
- if (value.privacy !== oldValue.privacy)
- setPrivacy({ privacy: value.privacy });
- });
- onMounted(() => {
- preventCloseUnsaved[props.modalUuid] = () =>
- displayNameUnsaved.value.length + privacyUnsaved.value.length > 0;
- });
- onBeforeUnmount(() => {
- delete preventCloseUnsaved[props.modalUuid];
- });
- </script>
- <template>
- <div class="settings-tab section">
- <div
- v-if="
- isEditable('playlists.update.displayName') &&
- !(
- playlist.type === 'user-liked' ||
- playlist.type === 'user-disliked'
- )
- "
- >
- <label class="label"> Change display name </label>
- <div class="control is-grouped input-with-button">
- <p class="control is-expanded">
- <input
- v-model="displayNameInputs['displayName'].value"
- class="input"
- type="text"
- placeholder="Playlist Display Name"
- @keyup.enter="saveDisplayName()"
- />
- </p>
- <p class="control">
- <button
- class="button is-info"
- @click.prevent="saveDisplayName()"
- >
- Rename
- </button>
- </p>
- </div>
- </div>
- <div v-if="isEditable('playlists.update.privacy')">
- <label class="label"> Change privacy </label>
- <div class="control is-grouped input-with-button">
- <div class="control is-expanded select">
- <select v-model="privacyInputs['privacy'].value">
- <option value="private">Private</option>
- <option value="public">Public</option>
- </select>
- </div>
- <p class="control">
- <button
- class="button is-info"
- @click.prevent="savePrivacy()"
- >
- Update Privacy
- </button>
- </p>
- </div>
- </div>
- </div>
- </template>
- <style lang="less" scoped>
- @media screen and (max-width: 1300px) {
- .section {
- max-width: 100% !important;
- }
- }
- </style>
|