You've already forked AstralRinth
forked from didirus/AstralRinth
Add TailwindCSS (#1252)
* Setup TailwindCSS * Fully setup configuration * Refactor some tailwind variables
This commit is contained in:
@@ -5,20 +5,20 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ChartDisplay from '~/components/ui/charts/ChartDisplay.vue'
|
||||
import ChartDisplay from "~/components/ui/charts/ChartDisplay.vue";
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'auth',
|
||||
})
|
||||
middleware: "auth",
|
||||
});
|
||||
|
||||
useHead({
|
||||
title: 'Analytics - Modrinth',
|
||||
})
|
||||
title: "Analytics - Modrinth",
|
||||
});
|
||||
|
||||
const auth = await useAuth()
|
||||
const id = auth.value?.user?.id
|
||||
const auth = await useAuth();
|
||||
const id = auth.value?.user?.id;
|
||||
|
||||
const { data: projects } = await useAsyncData(`user/${id}/projects`, () =>
|
||||
useBaseFetch(`user/${id}/projects`)
|
||||
)
|
||||
useBaseFetch(`user/${id}/projects`),
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -88,71 +88,71 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { BoxIcon, SearchIcon, XIcon, PlusIcon, LinkIcon, LockIcon } from '@modrinth/assets'
|
||||
import { Avatar, Button } from '@modrinth/ui'
|
||||
import WorldIcon from '~/assets/images/utils/world.svg?component'
|
||||
import CollectionCreateModal from '~/components/ui/CollectionCreateModal.vue'
|
||||
import { BoxIcon, SearchIcon, XIcon, PlusIcon, LinkIcon, LockIcon } from "@modrinth/assets";
|
||||
import { Avatar, Button } from "@modrinth/ui";
|
||||
import WorldIcon from "~/assets/images/utils/world.svg?component";
|
||||
import CollectionCreateModal from "~/components/ui/CollectionCreateModal.vue";
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatCompactNumber = useCompactNumber()
|
||||
const { formatMessage } = useVIntl();
|
||||
const formatCompactNumber = useCompactNumber();
|
||||
|
||||
const messages = defineMessages({
|
||||
createNewButton: {
|
||||
id: 'dashboard.collections.button.create-new',
|
||||
defaultMessage: 'Create new',
|
||||
id: "dashboard.collections.button.create-new",
|
||||
defaultMessage: "Create new",
|
||||
},
|
||||
collectionsLongTitle: {
|
||||
id: 'dashboard.collections.long-title',
|
||||
defaultMessage: 'Your collections',
|
||||
id: "dashboard.collections.long-title",
|
||||
defaultMessage: "Your collections",
|
||||
},
|
||||
followingCollectionDescription: {
|
||||
id: 'collection.description.following',
|
||||
id: "collection.description.following",
|
||||
defaultMessage: "Auto-generated collection of all the projects you're following.",
|
||||
},
|
||||
projectsCountLabel: {
|
||||
id: 'dashboard.collections.label.projects-count',
|
||||
defaultMessage: '{count, plural, one {{count} project} other {{count} projects}}',
|
||||
id: "dashboard.collections.label.projects-count",
|
||||
defaultMessage: "{count, plural, one {{count} project} other {{count} projects}}",
|
||||
},
|
||||
searchInputLabel: {
|
||||
id: 'dashboard.collections.label.search-input',
|
||||
defaultMessage: 'Search your collections',
|
||||
id: "dashboard.collections.label.search-input",
|
||||
defaultMessage: "Search your collections",
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'auth',
|
||||
})
|
||||
middleware: "auth",
|
||||
});
|
||||
|
||||
useHead({
|
||||
title: () => `${formatMessage(messages.collectionsLongTitle)} - Modrinth`,
|
||||
})
|
||||
});
|
||||
|
||||
const user = await useUser()
|
||||
const auth = await useAuth()
|
||||
const user = await useUser();
|
||||
const auth = await useAuth();
|
||||
|
||||
if (process.client) {
|
||||
await initUserFollows()
|
||||
await initUserFollows();
|
||||
}
|
||||
|
||||
const filterQuery = ref('')
|
||||
const filterQuery = ref("");
|
||||
|
||||
const { data: collections } = await useAsyncData(`user/${auth.value.user.id}/collections`, () =>
|
||||
useBaseFetch(`user/${auth.value.user.id}/collections`, { apiVersion: 3 })
|
||||
)
|
||||
useBaseFetch(`user/${auth.value.user.id}/collections`, { apiVersion: 3 }),
|
||||
);
|
||||
|
||||
const orderedCollections = computed(() => {
|
||||
if (!collections.value) return []
|
||||
if (!collections.value) return [];
|
||||
return collections.value
|
||||
.sort((a, b) => {
|
||||
const aUpdated = new Date(a.updated)
|
||||
const bUpdated = new Date(b.updated)
|
||||
return bUpdated - aUpdated
|
||||
const aUpdated = new Date(a.updated);
|
||||
const bUpdated = new Date(b.updated);
|
||||
return bUpdated - aUpdated;
|
||||
})
|
||||
.filter((collection) => {
|
||||
if (!filterQuery.value) return true
|
||||
return collection.name.toLowerCase().includes(filterQuery.value.toLowerCase())
|
||||
})
|
||||
})
|
||||
if (!filterQuery.value) return true;
|
||||
return collection.name.toLowerCase().includes(filterQuery.value.toLowerCase());
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.collections-grid {
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
class="goto-link view-more-notifs"
|
||||
to="/dashboard/notifications"
|
||||
>
|
||||
View {{ extraNotifs }} more notification{{ extraNotifs === 1 ? '' : 's' }}
|
||||
View {{ extraNotifs }} more notification{{ extraNotifs === 1 ? "" : "s" }}
|
||||
<ChevronRightIcon />
|
||||
</nuxt-link>
|
||||
</template>
|
||||
@@ -66,7 +66,7 @@
|
||||
<span
|
||||
>from
|
||||
{{ downloadsProjectCount }}
|
||||
project{{ downloadsProjectCount === 1 ? '' : 's' }}</span
|
||||
project{{ downloadsProjectCount === 1 ? "" : "s" }}</span
|
||||
>
|
||||
<!-- <NuxtLink class="goto-link" to="/dashboard/analytics"-->
|
||||
<!-- >View breakdown-->
|
||||
@@ -83,7 +83,7 @@
|
||||
<span>
|
||||
<span
|
||||
>from {{ followersProjectCount }} project{{
|
||||
followersProjectCount === 1 ? '' : 's'
|
||||
followersProjectCount === 1 ? "" : "s"
|
||||
}}</span
|
||||
></span
|
||||
>
|
||||
@@ -108,58 +108,58 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import ChevronRightIcon from '~/assets/images/utils/chevron-right.svg?component'
|
||||
import HistoryIcon from '~/assets/images/utils/history.svg?component'
|
||||
import Avatar from '~/components/ui/Avatar.vue'
|
||||
import NotificationItem from '~/components/ui/NotificationItem.vue'
|
||||
import { fetchExtraNotificationData, groupNotifications } from '~/helpers/notifications.js'
|
||||
import ChevronRightIcon from "~/assets/images/utils/chevron-right.svg?component";
|
||||
import HistoryIcon from "~/assets/images/utils/history.svg?component";
|
||||
import Avatar from "~/components/ui/Avatar.vue";
|
||||
import NotificationItem from "~/components/ui/NotificationItem.vue";
|
||||
import { fetchExtraNotificationData, groupNotifications } from "~/helpers/notifications.js";
|
||||
|
||||
useHead({
|
||||
title: 'Dashboard - Modrinth',
|
||||
})
|
||||
title: "Dashboard - Modrinth",
|
||||
});
|
||||
|
||||
const auth = await useAuth()
|
||||
const auth = await useAuth();
|
||||
|
||||
const [{ data: projects }] = await Promise.all([
|
||||
useAsyncData(`user/${auth.value.user.id}/projects`, () =>
|
||||
useBaseFetch(`user/${auth.value.user.id}/projects`)
|
||||
useBaseFetch(`user/${auth.value.user.id}/projects`),
|
||||
),
|
||||
])
|
||||
]);
|
||||
|
||||
const downloadsProjectCount = computed(
|
||||
() => projects.value.filter((project) => project.downloads > 0).length
|
||||
)
|
||||
() => projects.value.filter((project) => project.downloads > 0).length,
|
||||
);
|
||||
const followersProjectCount = computed(
|
||||
() => projects.value.filter((project) => project.followers > 0).length
|
||||
)
|
||||
() => projects.value.filter((project) => project.followers > 0).length,
|
||||
);
|
||||
|
||||
const { data, refresh } = await useAsyncData(async () => {
|
||||
const notifications = await useBaseFetch(`user/${auth.value.user.id}/notifications`)
|
||||
const notifications = await useBaseFetch(`user/${auth.value.user.id}/notifications`);
|
||||
|
||||
const filteredNotifications = notifications.filter((notif) => !notif.read)
|
||||
const slice = filteredNotifications.slice(0, 30) // send first 30 notifs to be grouped before trimming to 3
|
||||
const filteredNotifications = notifications.filter((notif) => !notif.read);
|
||||
const slice = filteredNotifications.slice(0, 30); // send first 30 notifs to be grouped before trimming to 3
|
||||
|
||||
return fetchExtraNotificationData(slice).then((notifications) => {
|
||||
notifications = groupNotifications(notifications).slice(0, 3)
|
||||
return { notifications, extraNotifs: filteredNotifications.length - slice.length }
|
||||
})
|
||||
})
|
||||
notifications = groupNotifications(notifications).slice(0, 3);
|
||||
return { notifications, extraNotifs: filteredNotifications.length - slice.length };
|
||||
});
|
||||
});
|
||||
|
||||
const notifications = computed(() => {
|
||||
if (data.value === null) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
return data.value.notifications
|
||||
})
|
||||
return data.value.notifications;
|
||||
});
|
||||
|
||||
const extraNotifs = computed(() => (data.value ? data.value.extraNotifs : 0))
|
||||
const extraNotifs = computed(() => (data.value ? data.value.extraNotifs : 0));
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.dashboard-overview {
|
||||
display: grid;
|
||||
grid-template:
|
||||
'header header'
|
||||
'notifications analytics' / 1fr auto;
|
||||
"header header"
|
||||
"notifications analytics" / 1fr auto;
|
||||
gap: var(--spacing-card-md);
|
||||
|
||||
> .universal-card {
|
||||
|
||||
@@ -50,110 +50,110 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Button } from '@modrinth/ui'
|
||||
import { HistoryIcon } from '@modrinth/assets'
|
||||
import { Button } from "@modrinth/ui";
|
||||
import { HistoryIcon } from "@modrinth/assets";
|
||||
import {
|
||||
fetchExtraNotificationData,
|
||||
groupNotifications,
|
||||
markAsRead,
|
||||
} from '~/helpers/notifications.js'
|
||||
import NotificationItem from '~/components/ui/NotificationItem.vue'
|
||||
import Chips from '~/components/ui/Chips.vue'
|
||||
import CheckCheckIcon from '~/assets/images/utils/check-check.svg?component'
|
||||
import Breadcrumbs from '~/components/ui/Breadcrumbs.vue'
|
||||
import Pagination from '~/components/ui/Pagination.vue'
|
||||
} from "~/helpers/notifications.js";
|
||||
import NotificationItem from "~/components/ui/NotificationItem.vue";
|
||||
import Chips from "~/components/ui/Chips.vue";
|
||||
import CheckCheckIcon from "~/assets/images/utils/check-check.svg?component";
|
||||
import Breadcrumbs from "~/components/ui/Breadcrumbs.vue";
|
||||
import Pagination from "~/components/ui/Pagination.vue";
|
||||
|
||||
useHead({
|
||||
title: 'Notifications - Modrinth',
|
||||
})
|
||||
title: "Notifications - Modrinth",
|
||||
});
|
||||
|
||||
const auth = await useAuth()
|
||||
const auth = await useAuth();
|
||||
|
||||
const route = useNativeRoute()
|
||||
const router = useNativeRouter()
|
||||
const route = useNativeRoute();
|
||||
const router = useNativeRouter();
|
||||
|
||||
const history = computed(() => {
|
||||
return route.name === 'dashboard-notifications-history'
|
||||
})
|
||||
return route.name === "dashboard-notifications-history";
|
||||
});
|
||||
|
||||
const selectedType = ref('all')
|
||||
const page = ref(1)
|
||||
const selectedType = ref("all");
|
||||
const page = ref(1);
|
||||
|
||||
const perPage = ref(50)
|
||||
const perPage = ref(50);
|
||||
|
||||
const { data, pending, error, refresh } = await useAsyncData(
|
||||
async () => {
|
||||
const pageNum = page.value - 1
|
||||
const pageNum = page.value - 1;
|
||||
|
||||
const notifications = await useBaseFetch(`user/${auth.value.user.id}/notifications`)
|
||||
const showRead = history.value
|
||||
const hasRead = notifications.some((notif) => notif.read)
|
||||
const notifications = await useBaseFetch(`user/${auth.value.user.id}/notifications`);
|
||||
const showRead = history.value;
|
||||
const hasRead = notifications.some((notif) => notif.read);
|
||||
|
||||
const types = [
|
||||
...new Set(
|
||||
notifications
|
||||
.filter((notification) => {
|
||||
return showRead || !notification.read
|
||||
return showRead || !notification.read;
|
||||
})
|
||||
.map((notification) => notification.type)
|
||||
.map((notification) => notification.type),
|
||||
),
|
||||
]
|
||||
];
|
||||
|
||||
const filteredNotifications = notifications.filter(
|
||||
(notification) =>
|
||||
(selectedType.value === 'all' || notification.type === selectedType.value) &&
|
||||
(showRead || !notification.read)
|
||||
)
|
||||
const pages = Math.ceil(filteredNotifications.length / perPage.value)
|
||||
(selectedType.value === "all" || notification.type === selectedType.value) &&
|
||||
(showRead || !notification.read),
|
||||
);
|
||||
const pages = Math.ceil(filteredNotifications.length / perPage.value);
|
||||
|
||||
return fetchExtraNotificationData(
|
||||
filteredNotifications.slice(pageNum * perPage.value, perPage.value + pageNum * perPage.value)
|
||||
filteredNotifications.slice(pageNum * perPage.value, perPage.value + pageNum * perPage.value),
|
||||
).then((notifications) => {
|
||||
return {
|
||||
notifications,
|
||||
types: types.length > 1 ? ['all', ...types] : types,
|
||||
types: types.length > 1 ? ["all", ...types] : types,
|
||||
pages,
|
||||
hasRead,
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
},
|
||||
{ watch: [page, history, selectedType] }
|
||||
)
|
||||
{ watch: [page, history, selectedType] },
|
||||
);
|
||||
|
||||
const notifications = computed(() => {
|
||||
if (data.value === null) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
return groupNotifications(data.value.notifications, history.value)
|
||||
})
|
||||
const notifTypes = computed(() => data.value.types)
|
||||
const pages = computed(() => data.value.pages)
|
||||
const hasRead = computed(() => data.value.hasRead)
|
||||
return groupNotifications(data.value.notifications, history.value);
|
||||
});
|
||||
const notifTypes = computed(() => data.value.types);
|
||||
const pages = computed(() => data.value.pages);
|
||||
const hasRead = computed(() => data.value.hasRead);
|
||||
|
||||
function updateRoute() {
|
||||
if (history.value) {
|
||||
router.push('/dashboard/notifications')
|
||||
router.push("/dashboard/notifications");
|
||||
} else {
|
||||
router.push('/dashboard/notifications/history')
|
||||
router.push("/dashboard/notifications/history");
|
||||
}
|
||||
selectedType.value = 'all'
|
||||
page.value = 1
|
||||
selectedType.value = "all";
|
||||
page.value = 1;
|
||||
}
|
||||
|
||||
async function readAll() {
|
||||
const ids = notifications.value.flatMap((notification) => [
|
||||
notification.id,
|
||||
...(notification.grouped_notifs ? notification.grouped_notifs.map((notif) => notif.id) : []),
|
||||
])
|
||||
]);
|
||||
|
||||
const updateNotifs = await markAsRead(ids)
|
||||
allNotifs.value = updateNotifs(allNotifs.value)
|
||||
const updateNotifs = await markAsRead(ids);
|
||||
allNotifs.value = updateNotifs(allNotifs.value);
|
||||
}
|
||||
|
||||
function changePage(newPage) {
|
||||
page.value = newPage
|
||||
page.value = newPage;
|
||||
if (process.client) {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -49,36 +49,36 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { PlusIcon, UsersIcon } from '@modrinth/assets'
|
||||
import { Avatar } from '@modrinth/ui'
|
||||
import { useAuth } from '~/composables/auth.js'
|
||||
import OrganizationCreateModal from '~/components/ui/OrganizationCreateModal.vue'
|
||||
import { PlusIcon, UsersIcon } from "@modrinth/assets";
|
||||
import { Avatar } from "@modrinth/ui";
|
||||
import { useAuth } from "~/composables/auth.js";
|
||||
import OrganizationCreateModal from "~/components/ui/OrganizationCreateModal.vue";
|
||||
|
||||
const createOrgModal = ref(null)
|
||||
const createOrgModal = ref(null);
|
||||
|
||||
const auth = await useAuth()
|
||||
const uid = computed(() => auth.value.user?.id || null)
|
||||
const auth = await useAuth();
|
||||
const uid = computed(() => auth.value.user?.id || null);
|
||||
|
||||
const { data: orgs, error } = useAsyncData('organizations', () => {
|
||||
if (!uid.value) return Promise.resolve(null)
|
||||
const { data: orgs, error } = useAsyncData("organizations", () => {
|
||||
if (!uid.value) return Promise.resolve(null);
|
||||
|
||||
return useBaseFetch('user/' + uid.value + '/organizations', {
|
||||
return useBaseFetch("user/" + uid.value + "/organizations", {
|
||||
apiVersion: 3,
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
const onlyAcceptedMembers = (members) => members.filter((member) => member?.accepted)
|
||||
const onlyAcceptedMembers = (members) => members.filter((member) => member?.accepted);
|
||||
|
||||
if (error.value) {
|
||||
createError({
|
||||
statusCode: 500,
|
||||
message: 'Failed to fetch organizations',
|
||||
})
|
||||
message: "Failed to fetch organizations",
|
||||
});
|
||||
}
|
||||
|
||||
const openCreateOrgModal = () => {
|
||||
createOrgModal.value?.show()
|
||||
}
|
||||
createOrgModal.value?.show();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -119,14 +119,14 @@
|
||||
<p>
|
||||
Changes will be applied to
|
||||
<strong>{{ selectedProjects.length }}</strong> project{{
|
||||
selectedProjects.length > 1 ? 's' : ''
|
||||
selectedProjects.length > 1 ? "s" : ""
|
||||
}}.
|
||||
</p>
|
||||
<ul>
|
||||
<li
|
||||
v-for="project in selectedProjects.slice(
|
||||
0,
|
||||
editLinks.showAffected ? selectedProjects.length : 3
|
||||
editLinks.showAffected ? selectedProjects.length : 3,
|
||||
)"
|
||||
:key="project.id"
|
||||
>
|
||||
@@ -300,24 +300,24 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
|
||||
import Badge from '~/components/ui/Badge.vue'
|
||||
import Checkbox from '~/components/ui/Checkbox.vue'
|
||||
import Modal from '~/components/ui/Modal.vue'
|
||||
import Avatar from '~/components/ui/Avatar.vue'
|
||||
import ModalCreation from '~/components/ui/ModalCreation.vue'
|
||||
import CopyCode from '~/components/ui/CopyCode.vue'
|
||||
import Badge from "~/components/ui/Badge.vue";
|
||||
import Checkbox from "~/components/ui/Checkbox.vue";
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
import Avatar from "~/components/ui/Avatar.vue";
|
||||
import ModalCreation from "~/components/ui/ModalCreation.vue";
|
||||
import CopyCode from "~/components/ui/CopyCode.vue";
|
||||
|
||||
import SettingsIcon from '~/assets/images/utils/settings.svg?component'
|
||||
import TrashIcon from '~/assets/images/utils/trash.svg?component'
|
||||
import IssuesIcon from '~/assets/images/utils/issues.svg?component'
|
||||
import PlusIcon from '~/assets/images/utils/plus.svg?component'
|
||||
import CrossIcon from '~/assets/images/utils/x.svg?component'
|
||||
import EditIcon from '~/assets/images/utils/edit.svg?component'
|
||||
import SaveIcon from '~/assets/images/utils/save.svg?component'
|
||||
import AscendingIcon from '~/assets/images/utils/sort-asc.svg?component'
|
||||
import DescendingIcon from '~/assets/images/utils/sort-desc.svg?component'
|
||||
import SettingsIcon from "~/assets/images/utils/settings.svg?component";
|
||||
import TrashIcon from "~/assets/images/utils/trash.svg?component";
|
||||
import IssuesIcon from "~/assets/images/utils/issues.svg?component";
|
||||
import PlusIcon from "~/assets/images/utils/plus.svg?component";
|
||||
import CrossIcon from "~/assets/images/utils/x.svg?component";
|
||||
import EditIcon from "~/assets/images/utils/edit.svg?component";
|
||||
import SaveIcon from "~/assets/images/utils/save.svg?component";
|
||||
import AscendingIcon from "~/assets/images/utils/sort-asc.svg?component";
|
||||
import DescendingIcon from "~/assets/images/utils/sort-desc.svg?component";
|
||||
|
||||
export default defineNuxtComponent({
|
||||
components: {
|
||||
@@ -339,97 +339,97 @@ export default defineNuxtComponent({
|
||||
DescendingIcon,
|
||||
},
|
||||
async setup() {
|
||||
const { formatMessage } = useVIntl()
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const user = await useUser()
|
||||
await initUserProjects()
|
||||
return { formatMessage, user: ref(user) }
|
||||
const user = await useUser();
|
||||
await initUserProjects();
|
||||
return { formatMessage, user: ref(user) };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projects: this.updateSort(this.user.projects, 'Name'),
|
||||
projects: this.updateSort(this.user.projects, "Name"),
|
||||
versions: [],
|
||||
selectedProjects: [],
|
||||
sortBy: 'Name',
|
||||
sortBy: "Name",
|
||||
descending: false,
|
||||
editLinks: {
|
||||
showAffected: false,
|
||||
source: {
|
||||
val: '',
|
||||
val: "",
|
||||
clear: false,
|
||||
},
|
||||
discord: {
|
||||
val: '',
|
||||
val: "",
|
||||
clear: false,
|
||||
},
|
||||
wiki: {
|
||||
val: '',
|
||||
val: "",
|
||||
clear: false,
|
||||
},
|
||||
issues: {
|
||||
val: '',
|
||||
val: "",
|
||||
clear: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
head: {
|
||||
title: 'Projects - Modrinth',
|
||||
title: "Projects - Modrinth",
|
||||
},
|
||||
created() {
|
||||
this.UPLOAD_VERSION = 1 << 0
|
||||
this.DELETE_VERSION = 1 << 1
|
||||
this.EDIT_DETAILS = 1 << 2
|
||||
this.EDIT_BODY = 1 << 3
|
||||
this.MANAGE_INVITES = 1 << 4
|
||||
this.REMOVE_MEMBER = 1 << 5
|
||||
this.EDIT_MEMBER = 1 << 6
|
||||
this.DELETE_PROJECT = 1 << 7
|
||||
this.UPLOAD_VERSION = 1 << 0;
|
||||
this.DELETE_VERSION = 1 << 1;
|
||||
this.EDIT_DETAILS = 1 << 2;
|
||||
this.EDIT_BODY = 1 << 3;
|
||||
this.MANAGE_INVITES = 1 << 4;
|
||||
this.REMOVE_MEMBER = 1 << 5;
|
||||
this.EDIT_MEMBER = 1 << 6;
|
||||
this.DELETE_PROJECT = 1 << 7;
|
||||
},
|
||||
methods: {
|
||||
updateDescending() {
|
||||
this.descending = !this.descending
|
||||
this.projects = this.updateSort(this.projects, this.sortBy, this.descending)
|
||||
this.descending = !this.descending;
|
||||
this.projects = this.updateSort(this.projects, this.sortBy, this.descending);
|
||||
},
|
||||
updateSort(projects, sort, descending) {
|
||||
let sortedArray = projects
|
||||
let sortedArray = projects;
|
||||
switch (sort) {
|
||||
case 'Name':
|
||||
case "Name":
|
||||
sortedArray = projects.slice().sort((a, b) => {
|
||||
return a.title.localeCompare(b.title)
|
||||
})
|
||||
break
|
||||
case 'Status':
|
||||
return a.title.localeCompare(b.title);
|
||||
});
|
||||
break;
|
||||
case "Status":
|
||||
sortedArray = projects.slice().sort((a, b) => {
|
||||
if (a.status < b.status) {
|
||||
return -1
|
||||
return -1;
|
||||
}
|
||||
if (a.status > b.status) {
|
||||
return 1
|
||||
return 1;
|
||||
}
|
||||
return 0
|
||||
})
|
||||
break
|
||||
case 'Type':
|
||||
return 0;
|
||||
});
|
||||
break;
|
||||
case "Type":
|
||||
sortedArray = projects.slice().sort((a, b) => {
|
||||
if (a.project_type < b.project_type) {
|
||||
return -1
|
||||
return -1;
|
||||
}
|
||||
if (a.project_type > b.project_type) {
|
||||
return 1
|
||||
return 1;
|
||||
}
|
||||
return 0
|
||||
})
|
||||
break
|
||||
return 0;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break
|
||||
break;
|
||||
}
|
||||
|
||||
if (descending) {
|
||||
sortedArray = sortedArray.reverse()
|
||||
sortedArray = sortedArray.reverse();
|
||||
}
|
||||
|
||||
return sortedArray
|
||||
return sortedArray;
|
||||
},
|
||||
async bulkEditLinks() {
|
||||
try {
|
||||
@@ -438,60 +438,60 @@ export default defineNuxtComponent({
|
||||
source_url: this.editLinks.source.clear ? null : this.editLinks.source.val.trim(),
|
||||
wiki_url: this.editLinks.wiki.clear ? null : this.editLinks.wiki.val.trim(),
|
||||
discord_url: this.editLinks.discord.clear ? null : this.editLinks.discord.val.trim(),
|
||||
}
|
||||
};
|
||||
|
||||
if (!baseData.issues_url?.length ?? 1 > 0) {
|
||||
delete baseData.issues_url
|
||||
delete baseData.issues_url;
|
||||
}
|
||||
|
||||
if (!baseData.source_url?.length ?? 1 > 0) {
|
||||
delete baseData.source_url
|
||||
delete baseData.source_url;
|
||||
}
|
||||
|
||||
if (!baseData.wiki_url?.length ?? 1 > 0) {
|
||||
delete baseData.wiki_url
|
||||
delete baseData.wiki_url;
|
||||
}
|
||||
|
||||
if (!baseData.discord_url?.length ?? 1 > 0) {
|
||||
delete baseData.discord_url
|
||||
delete baseData.discord_url;
|
||||
}
|
||||
|
||||
await useBaseFetch(
|
||||
`projects?ids=${JSON.stringify(this.selectedProjects.map((x) => x.id))}`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
method: "PATCH",
|
||||
body: baseData,
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
this.$refs.editLinksModal.hide()
|
||||
this.$refs.editLinksModal.hide();
|
||||
this.$notify({
|
||||
group: 'main',
|
||||
title: 'Success',
|
||||
group: "main",
|
||||
title: "Success",
|
||||
text: "Bulk edited selected project's links.",
|
||||
type: 'success',
|
||||
})
|
||||
this.selectedProjects = []
|
||||
type: "success",
|
||||
});
|
||||
this.selectedProjects = [];
|
||||
|
||||
this.editLinks.issues.val = ''
|
||||
this.editLinks.source.val = ''
|
||||
this.editLinks.wiki.val = ''
|
||||
this.editLinks.discord.val = ''
|
||||
this.editLinks.issues.clear = false
|
||||
this.editLinks.source.clear = false
|
||||
this.editLinks.wiki.clear = false
|
||||
this.editLinks.discord.clear = false
|
||||
this.editLinks.issues.val = "";
|
||||
this.editLinks.source.val = "";
|
||||
this.editLinks.wiki.val = "";
|
||||
this.editLinks.discord.val = "";
|
||||
this.editLinks.issues.clear = false;
|
||||
this.editLinks.source.clear = false;
|
||||
this.editLinks.wiki.clear = false;
|
||||
this.editLinks.discord.clear = false;
|
||||
} catch (e) {
|
||||
this.$notify({
|
||||
group: 'main',
|
||||
title: 'An error occurred',
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: e,
|
||||
type: 'error',
|
||||
})
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.grid-table {
|
||||
@@ -543,7 +543,7 @@ export default defineNuxtComponent({
|
||||
|
||||
.grid-table__row {
|
||||
display: grid;
|
||||
grid-template: 'checkbox icon name type settings' 'checkbox icon id status settings';
|
||||
grid-template: "checkbox icon name type settings" "checkbox icon id status settings";
|
||||
grid-template-columns:
|
||||
min-content min-content minmax(min-content, 2fr)
|
||||
minmax(min-content, 1fr) min-content;
|
||||
@@ -580,7 +580,7 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
.grid-table__header {
|
||||
grid-template: 'checkbox settings';
|
||||
grid-template: "checkbox settings";
|
||||
grid-template-columns: min-content minmax(min-content, 1fr);
|
||||
|
||||
:nth-child(2),
|
||||
@@ -596,7 +596,7 @@ export default defineNuxtComponent({
|
||||
@media screen and (max-width: 560px) {
|
||||
.grid-table__row {
|
||||
display: grid;
|
||||
grid-template: 'checkbox icon name settings' 'checkbox icon id settings' 'checkbox icon type settings' 'checkbox icon status settings';
|
||||
grid-template: "checkbox icon name settings" "checkbox icon id settings" "checkbox icon type settings" "checkbox icon status settings";
|
||||
grid-template-columns: min-content min-content minmax(min-content, 1fr) min-content;
|
||||
|
||||
:nth-child(5) {
|
||||
@@ -605,7 +605,7 @@ export default defineNuxtComponent({
|
||||
}
|
||||
|
||||
.grid-table__header {
|
||||
grid-template: 'checkbox settings';
|
||||
grid-template: "checkbox settings";
|
||||
grid-template-columns: min-content minmax(min-content, 1fr);
|
||||
}
|
||||
}
|
||||
@@ -644,7 +644,7 @@ export default defineNuxtComponent({
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.label-button[data-active='true'] {
|
||||
.label-button[data-active="true"] {
|
||||
--background-color: var(--color-red);
|
||||
--text-color: var(--color-brand-inverted);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import ReportView from '~/components/ui/report/ReportView.vue'
|
||||
import ReportView from "~/components/ui/report/ReportView.vue";
|
||||
|
||||
const route = useNativeRoute()
|
||||
const auth = await useAuth()
|
||||
const route = useNativeRoute();
|
||||
const auth = await useAuth();
|
||||
|
||||
useHead({
|
||||
title: `Report ${route.params.id} - Modrinth`,
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import ReportsList from '~/components/ui/report/ReportsList.vue'
|
||||
import ReportsList from "~/components/ui/report/ReportsList.vue";
|
||||
|
||||
const auth = await useAuth()
|
||||
const auth = await useAuth();
|
||||
useHead({
|
||||
title: 'Active reports - Modrinth',
|
||||
})
|
||||
title: "Active reports - Modrinth",
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -75,34 +75,34 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { TransferIcon, HistoryIcon, PayPalIcon, SaveIcon, XIcon } from '@modrinth/assets'
|
||||
import { TransferIcon, HistoryIcon, PayPalIcon, SaveIcon, XIcon } from "@modrinth/assets";
|
||||
|
||||
const auth = await useAuth()
|
||||
const minWithdraw = ref(0.01)
|
||||
const auth = await useAuth();
|
||||
const minWithdraw = ref(0.01);
|
||||
|
||||
async function updateVenmo() {
|
||||
startLoading()
|
||||
startLoading();
|
||||
try {
|
||||
const data = {
|
||||
venmo_handle: auth.value.user.payout_data.venmo_handle ?? null,
|
||||
}
|
||||
};
|
||||
|
||||
await useBaseFetch(`user/${auth.value.user.id}`, {
|
||||
method: 'PATCH',
|
||||
method: "PATCH",
|
||||
body: data,
|
||||
apiVersion: 3,
|
||||
})
|
||||
await useAuth(auth.value.token)
|
||||
});
|
||||
await useAuth(auth.value.token);
|
||||
} catch (err) {
|
||||
const data = useNuxtApp()
|
||||
const data = useNuxtApp();
|
||||
data.$notify({
|
||||
group: 'main',
|
||||
title: 'An error occurred',
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err.data.description,
|
||||
type: 'error',
|
||||
})
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
stopLoading()
|
||||
stopLoading();
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
</div>
|
||||
<p>
|
||||
{{
|
||||
selectedYear !== 'all'
|
||||
? selectedMethod !== 'all'
|
||||
selectedYear !== "all"
|
||||
? selectedMethod !== "all"
|
||||
? formatMessage(messages.transfersTotalYearMethod, {
|
||||
amount: $formatMoney(totalAmount),
|
||||
year: selectedYear,
|
||||
@@ -36,12 +36,12 @@
|
||||
amount: $formatMoney(totalAmount),
|
||||
year: selectedYear,
|
||||
})
|
||||
: selectedMethod !== 'all'
|
||||
? formatMessage(messages.transfersTotalMethod, {
|
||||
amount: $formatMoney(totalAmount),
|
||||
method: selectedMethod,
|
||||
})
|
||||
: formatMessage(messages.transfersTotal, { amount: $formatMoney(totalAmount) })
|
||||
: selectedMethod !== "all"
|
||||
? formatMessage(messages.transfersTotalMethod, {
|
||||
amount: $formatMoney(totalAmount),
|
||||
method: selectedMethod,
|
||||
})
|
||||
: formatMessage(messages.transfersTotal, { amount: $formatMoney(totalAmount) })
|
||||
}}
|
||||
</p>
|
||||
<div
|
||||
@@ -58,7 +58,7 @@
|
||||
<div class="payout-info">
|
||||
<div>
|
||||
<strong>
|
||||
{{ $dayjs(payout.created).format('MMMM D, YYYY [at] h:mm A') }}
|
||||
{{ $dayjs(payout.created).format("MMMM D, YYYY [at] h:mm A") }}
|
||||
</strong>
|
||||
</div>
|
||||
<div>
|
||||
@@ -94,96 +94,96 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { DropdownSelect } from '@modrinth/ui'
|
||||
import { XIcon, PayPalIcon, UnknownIcon } from '@modrinth/assets'
|
||||
import { capitalizeString } from '@modrinth/utils'
|
||||
import { Badge, Breadcrumbs } from '@modrinth/ui'
|
||||
import dayjs from 'dayjs'
|
||||
import TremendousIcon from '~/assets/images/external/tremendous.svg?component'
|
||||
import VenmoIcon from '~/assets/images/external/venmo-small.svg?component'
|
||||
import { DropdownSelect } from "@modrinth/ui";
|
||||
import { XIcon, PayPalIcon, UnknownIcon } from "@modrinth/assets";
|
||||
import { capitalizeString } from "@modrinth/utils";
|
||||
import { Badge, Breadcrumbs } from "@modrinth/ui";
|
||||
import dayjs from "dayjs";
|
||||
import TremendousIcon from "~/assets/images/external/tremendous.svg?component";
|
||||
import VenmoIcon from "~/assets/images/external/venmo-small.svg?component";
|
||||
|
||||
const vintl = useVIntl()
|
||||
const { formatMessage } = vintl
|
||||
const vintl = useVIntl();
|
||||
const { formatMessage } = vintl;
|
||||
|
||||
useHead({
|
||||
title: 'Transfer history - Modrinth',
|
||||
})
|
||||
title: "Transfer history - Modrinth",
|
||||
});
|
||||
|
||||
const data = await useNuxtApp()
|
||||
const auth = await useAuth()
|
||||
const data = await useNuxtApp();
|
||||
const auth = await useAuth();
|
||||
|
||||
const { data: payouts, refresh } = await useAsyncData(`payout`, () =>
|
||||
useBaseFetch(`payout`, {
|
||||
apiVersion: 3,
|
||||
})
|
||||
)
|
||||
}),
|
||||
);
|
||||
|
||||
const sortedPayouts = computed(() =>
|
||||
payouts.value.sort((a, b) => dayjs(b.created) - dayjs(a.created))
|
||||
)
|
||||
payouts.value.sort((a, b) => dayjs(b.created) - dayjs(a.created)),
|
||||
);
|
||||
|
||||
const years = computed(() => {
|
||||
const values = sortedPayouts.value.map((x) => dayjs(x.created).year())
|
||||
return ['all', ...new Set(values)]
|
||||
})
|
||||
const values = sortedPayouts.value.map((x) => dayjs(x.created).year());
|
||||
return ["all", ...new Set(values)];
|
||||
});
|
||||
|
||||
const selectedYear = ref('all')
|
||||
const selectedYear = ref("all");
|
||||
|
||||
const methods = computed(() => {
|
||||
const values = sortedPayouts.value.filter((x) => x.method).map((x) => x.method)
|
||||
return ['all', ...new Set(values)]
|
||||
})
|
||||
const values = sortedPayouts.value.filter((x) => x.method).map((x) => x.method);
|
||||
return ["all", ...new Set(values)];
|
||||
});
|
||||
|
||||
const selectedMethod = ref('all')
|
||||
const selectedMethod = ref("all");
|
||||
|
||||
const filteredPayouts = computed(() =>
|
||||
sortedPayouts.value
|
||||
.filter((x) => selectedYear.value === 'all' || dayjs(x.created).year() === selectedYear.value)
|
||||
.filter((x) => selectedMethod.value === 'all' || x.method === selectedMethod.value)
|
||||
)
|
||||
.filter((x) => selectedYear.value === "all" || dayjs(x.created).year() === selectedYear.value)
|
||||
.filter((x) => selectedMethod.value === "all" || x.method === selectedMethod.value),
|
||||
);
|
||||
|
||||
const totalAmount = computed(() =>
|
||||
filteredPayouts.value.reduce((sum, payout) => sum + payout.amount, 0)
|
||||
)
|
||||
filteredPayouts.value.reduce((sum, payout) => sum + payout.amount, 0),
|
||||
);
|
||||
|
||||
async function cancelPayout(id) {
|
||||
startLoading()
|
||||
startLoading();
|
||||
try {
|
||||
await useBaseFetch(`payout/${id}`, {
|
||||
method: 'DELETE',
|
||||
method: "DELETE",
|
||||
apiVersion: 3,
|
||||
})
|
||||
await refresh()
|
||||
await useAuth(auth.value.token)
|
||||
});
|
||||
await refresh();
|
||||
await useAuth(auth.value.token);
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: 'main',
|
||||
title: 'An error occurred',
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err.data.description,
|
||||
type: 'error',
|
||||
})
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
stopLoading()
|
||||
stopLoading();
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
transfersTotal: {
|
||||
id: 'revenue.transfers.total',
|
||||
defaultMessage: 'You have withdrawn {amount} in total.',
|
||||
id: "revenue.transfers.total",
|
||||
defaultMessage: "You have withdrawn {amount} in total.",
|
||||
},
|
||||
transfersTotalYear: {
|
||||
id: 'revenue.transfers.total.year',
|
||||
defaultMessage: 'You have withdrawn {amount} in {year}.',
|
||||
id: "revenue.transfers.total.year",
|
||||
defaultMessage: "You have withdrawn {amount} in {year}.",
|
||||
},
|
||||
transfersTotalMethod: {
|
||||
id: 'revenue.transfers.total.method',
|
||||
defaultMessage: 'You have withdrawn {amount} through {method}.',
|
||||
id: "revenue.transfers.total.method",
|
||||
defaultMessage: "You have withdrawn {amount} through {method}.",
|
||||
},
|
||||
transfersTotalYearMethod: {
|
||||
id: 'revenue.transfers.total.year_method',
|
||||
defaultMessage: 'You have withdrawn {amount} in {year} through {method}.',
|
||||
id: "revenue.transfers.total.year_method",
|
||||
defaultMessage: "You have withdrawn {amount} in {year} through {method}.",
|
||||
},
|
||||
})
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.payout {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="withdraw-options">
|
||||
<button
|
||||
v-for="method in payoutMethods.filter((x) =>
|
||||
x.name.toLowerCase().includes(search.toLowerCase())
|
||||
x.name.toLowerCase().includes(search.toLowerCase()),
|
||||
)"
|
||||
:key="method.id"
|
||||
class="withdraw-option button-base"
|
||||
@@ -53,8 +53,8 @@
|
||||
{{
|
||||
getRangeOfMethod(method)
|
||||
.map($formatMoney)
|
||||
.map((i) => i.replace('.00', ''))
|
||||
.join('–')
|
||||
.map((i) => i.replace(".00", ""))
|
||||
.join("–")
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
@@ -183,7 +183,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import {
|
||||
PayPalIcon,
|
||||
SearchIcon,
|
||||
@@ -191,182 +191,182 @@ import {
|
||||
RadioButtonChecked,
|
||||
XIcon,
|
||||
TransferIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Chips, Checkbox, Breadcrumbs } from '@modrinth/ui'
|
||||
import { all } from 'iso-3166-1'
|
||||
import VenmoIcon from '~/assets/images/external/venmo.svg?component'
|
||||
} from "@modrinth/assets";
|
||||
import { Chips, Checkbox, Breadcrumbs } from "@modrinth/ui";
|
||||
import { all } from "iso-3166-1";
|
||||
import VenmoIcon from "~/assets/images/external/venmo.svg?component";
|
||||
|
||||
const auth = await useAuth()
|
||||
const data = useNuxtApp()
|
||||
const auth = await useAuth();
|
||||
const data = useNuxtApp();
|
||||
|
||||
const countries = computed(() =>
|
||||
all().map((x) => ({
|
||||
id: x.alpha2,
|
||||
name: x.alpha2 === 'TW' ? 'Taiwan' : x.country,
|
||||
}))
|
||||
)
|
||||
const search = ref('')
|
||||
name: x.alpha2 === "TW" ? "Taiwan" : x.country,
|
||||
})),
|
||||
);
|
||||
const search = ref("");
|
||||
|
||||
const amount = ref('')
|
||||
const amount = ref("");
|
||||
const country = ref(
|
||||
countries.value.find((x) => x.id === (auth.value.user.payout_data.paypal_region ?? 'US'))
|
||||
)
|
||||
countries.value.find((x) => x.id === (auth.value.user.payout_data.paypal_region ?? "US")),
|
||||
);
|
||||
|
||||
const { data: payoutMethods, refresh: refreshPayoutMethods } = await useAsyncData(
|
||||
`payout/methods?country=${country.value.id}`,
|
||||
() => useBaseFetch(`payout/methods?country=${country.value.id}`, { apiVersion: 3 })
|
||||
)
|
||||
() => useBaseFetch(`payout/methods?country=${country.value.id}`, { apiVersion: 3 }),
|
||||
);
|
||||
|
||||
const selectedMethodId = ref(payoutMethods.value[0].id)
|
||||
const selectedMethodId = ref(payoutMethods.value[0].id);
|
||||
const selectedMethod = computed(() =>
|
||||
payoutMethods.value.find((x) => x.id === selectedMethodId.value)
|
||||
)
|
||||
payoutMethods.value.find((x) => x.id === selectedMethodId.value),
|
||||
);
|
||||
|
||||
const parsedAmount = computed(() => {
|
||||
const regex = /^\$?(\d*(\.\d{2})?)$/gm
|
||||
const matches = regex.exec(amount.value)
|
||||
return matches && matches[1] ? parseFloat(matches[1]) : 0.0
|
||||
})
|
||||
const regex = /^\$?(\d*(\.\d{2})?)$/gm;
|
||||
const matches = regex.exec(amount.value);
|
||||
return matches && matches[1] ? parseFloat(matches[1]) : 0.0;
|
||||
});
|
||||
const fees = computed(() => {
|
||||
return Math.min(
|
||||
Math.max(
|
||||
selectedMethod.value.fee.min,
|
||||
selectedMethod.value.fee.percentage * parsedAmount.value
|
||||
selectedMethod.value.fee.percentage * parsedAmount.value,
|
||||
),
|
||||
selectedMethod.value.fee.max ?? Number.MAX_VALUE
|
||||
)
|
||||
})
|
||||
selectedMethod.value.fee.max ?? Number.MAX_VALUE,
|
||||
);
|
||||
});
|
||||
|
||||
const getIntervalRange = (intervalType) => {
|
||||
if (!intervalType) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
|
||||
const { min, max, values } = intervalType
|
||||
const { min, max, values } = intervalType;
|
||||
if (values) {
|
||||
const first = values[0]
|
||||
const last = values.slice(-1)[0]
|
||||
return first === last ? [first] : [first, last]
|
||||
const first = values[0];
|
||||
const last = values.slice(-1)[0];
|
||||
return first === last ? [first] : [first, last];
|
||||
}
|
||||
|
||||
return min === max ? [min] : [min, max]
|
||||
}
|
||||
return min === max ? [min] : [min, max];
|
||||
};
|
||||
|
||||
const getRangeOfMethod = (method) => {
|
||||
return getIntervalRange(method.interval?.fixed || method.interval?.standard)
|
||||
}
|
||||
return getIntervalRange(method.interval?.fixed || method.interval?.standard);
|
||||
};
|
||||
|
||||
const maxWithdrawAmount = computed(() => {
|
||||
const interval = selectedMethod.value.interval
|
||||
return interval?.standard ? interval.standard.max : interval?.fixed?.values.slice(-1)[0] ?? 0
|
||||
})
|
||||
const interval = selectedMethod.value.interval;
|
||||
return interval?.standard ? interval.standard.max : interval?.fixed?.values.slice(-1)[0] ?? 0;
|
||||
});
|
||||
|
||||
const minWithdrawAmount = computed(() => {
|
||||
const interval = selectedMethod.value.interval
|
||||
return interval?.standard ? interval.standard.min : interval?.fixed?.values?.[0] ?? fees.value
|
||||
})
|
||||
const interval = selectedMethod.value.interval;
|
||||
return interval?.standard ? interval.standard.min : interval?.fixed?.values?.[0] ?? fees.value;
|
||||
});
|
||||
|
||||
const withdrawAccount = computed(() => {
|
||||
if (selectedMethod.value.type === 'paypal') {
|
||||
return auth.value.user.payout_data.paypal_address
|
||||
} else if (selectedMethod.value.type === 'venmo') {
|
||||
return auth.value.user.payout_data.venmo_handle
|
||||
if (selectedMethod.value.type === "paypal") {
|
||||
return auth.value.user.payout_data.paypal_address;
|
||||
} else if (selectedMethod.value.type === "venmo") {
|
||||
return auth.value.user.payout_data.venmo_handle;
|
||||
} else {
|
||||
return auth.value.user.email
|
||||
return auth.value.user.email;
|
||||
}
|
||||
})
|
||||
});
|
||||
const knownErrors = computed(() => {
|
||||
const errors = []
|
||||
if (selectedMethod.value.type === 'paypal' && !auth.value.user.payout_data.paypal_address) {
|
||||
errors.push('Please link your PayPal account in the dashboard to proceed.')
|
||||
const errors = [];
|
||||
if (selectedMethod.value.type === "paypal" && !auth.value.user.payout_data.paypal_address) {
|
||||
errors.push("Please link your PayPal account in the dashboard to proceed.");
|
||||
}
|
||||
if (selectedMethod.value.type === 'venmo' && !auth.value.user.payout_data.venmo_handle) {
|
||||
errors.push('Please set your Venmo handle in the dashboard to proceed.')
|
||||
if (selectedMethod.value.type === "venmo" && !auth.value.user.payout_data.venmo_handle) {
|
||||
errors.push("Please set your Venmo handle in the dashboard to proceed.");
|
||||
}
|
||||
if (selectedMethod.value.type === 'tremendous') {
|
||||
if (selectedMethod.value.type === "tremendous") {
|
||||
if (!auth.value.user.email) {
|
||||
errors.push('Please set your email address in your account settings to proceed.')
|
||||
errors.push("Please set your email address in your account settings to proceed.");
|
||||
}
|
||||
if (!auth.value.user.email_verified) {
|
||||
errors.push('Please verify your email address to proceed.')
|
||||
errors.push("Please verify your email address to proceed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!parsedAmount.value && amount.value.length > 0) {
|
||||
errors.push(`${amount.value} is not a valid amount`)
|
||||
errors.push(`${amount.value} is not a valid amount`);
|
||||
} else if (
|
||||
parsedAmount.value > auth.value.user.payout_data.balance ||
|
||||
parsedAmount.value > maxWithdrawAmount.value
|
||||
) {
|
||||
const maxAmount = Math.min(auth.value.user.payout_data.balance, maxWithdrawAmount.value)
|
||||
errors.push(`The amount must be no more than ${data.$formatMoney(maxAmount)}`)
|
||||
const maxAmount = Math.min(auth.value.user.payout_data.balance, maxWithdrawAmount.value);
|
||||
errors.push(`The amount must be no more than ${data.$formatMoney(maxAmount)}`);
|
||||
} else if (parsedAmount.value <= fees.value || parsedAmount.value < minWithdrawAmount.value) {
|
||||
const minAmount = Math.max(fees.value + 0.01, minWithdrawAmount.value)
|
||||
errors.push(`The amount must be at least ${data.$formatMoney(minAmount)}`)
|
||||
const minAmount = Math.max(fees.value + 0.01, minWithdrawAmount.value);
|
||||
errors.push(`The amount must be at least ${data.$formatMoney(minAmount)}`);
|
||||
}
|
||||
|
||||
return errors
|
||||
})
|
||||
return errors;
|
||||
});
|
||||
|
||||
const agreedTransfer = ref(false)
|
||||
const agreedFees = ref(false)
|
||||
const agreedTerms = ref(false)
|
||||
const agreedTransfer = ref(false);
|
||||
const agreedFees = ref(false);
|
||||
const agreedTerms = ref(false);
|
||||
|
||||
watch(country, async () => {
|
||||
await refreshPayoutMethods()
|
||||
await refreshPayoutMethods();
|
||||
if (payoutMethods.value && payoutMethods.value[0]) {
|
||||
selectedMethodId.value = payoutMethods.value[0].id
|
||||
selectedMethodId.value = payoutMethods.value[0].id;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
watch(selectedMethod, () => {
|
||||
if (selectedMethod.value.interval?.fixed) {
|
||||
amount.value = selectedMethod.value.interval.fixed.values[0]
|
||||
amount.value = selectedMethod.value.interval.fixed.values[0];
|
||||
}
|
||||
if (maxWithdrawAmount.value === minWithdrawAmount.value) {
|
||||
amount.value = maxWithdrawAmount.value
|
||||
amount.value = maxWithdrawAmount.value;
|
||||
}
|
||||
agreedTransfer.value = false
|
||||
agreedFees.value = false
|
||||
agreedTerms.value = false
|
||||
})
|
||||
agreedTransfer.value = false;
|
||||
agreedFees.value = false;
|
||||
agreedTerms.value = false;
|
||||
});
|
||||
|
||||
async function withdraw() {
|
||||
startLoading()
|
||||
startLoading();
|
||||
try {
|
||||
const auth = await useAuth()
|
||||
const auth = await useAuth();
|
||||
|
||||
await useBaseFetch(`payout`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
body: {
|
||||
amount: parsedAmount.value,
|
||||
method: selectedMethod.value.type,
|
||||
method_id: selectedMethod.value.id,
|
||||
},
|
||||
apiVersion: 3,
|
||||
})
|
||||
await useAuth(auth.value.token)
|
||||
await navigateTo('/dashboard/revenue')
|
||||
});
|
||||
await useAuth(auth.value.token);
|
||||
await navigateTo("/dashboard/revenue");
|
||||
data.$notify({
|
||||
group: 'main',
|
||||
title: 'Withdrawal complete',
|
||||
group: "main",
|
||||
title: "Withdrawal complete",
|
||||
text:
|
||||
selectedMethod.value.type === 'tremendous'
|
||||
? 'An email has been sent to your account with further instructions on how to redeem your payout!'
|
||||
selectedMethod.value.type === "tremendous"
|
||||
? "An email has been sent to your account with further instructions on how to redeem your payout!"
|
||||
: `Payment has been sent to your ${data.$formatWallet(
|
||||
selectedMethod.value.type
|
||||
selectedMethod.value.type,
|
||||
)} account!`,
|
||||
type: 'success',
|
||||
})
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: 'main',
|
||||
title: 'An error occurred',
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err.data.description,
|
||||
type: 'error',
|
||||
})
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
stopLoading()
|
||||
stopLoading();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user