mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-15 11:42:15 +01:00
add frontend format support for currencies, add currencies endpoint
This commit is contained in:
committed by
Constantin Graf
parent
c1d43bcc67
commit
f69bc28316
@@ -2,10 +2,14 @@
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import BillableRateModal from '@/packages/ui/src/BillableRateModal.vue';
|
||||
import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
import { inject, type ComputedRef } from 'vue';
|
||||
import type { Organization } from '@/packages/api/src';
|
||||
|
||||
const show = defineModel('show', { default: false });
|
||||
const saving = defineModel('saving', { default: false });
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
|
||||
defineProps<{
|
||||
newBillableRate?: number | null;
|
||||
memberName: string;
|
||||
@@ -28,7 +32,10 @@ defineEmits<{
|
||||
newBillableRate
|
||||
? formatCents(
|
||||
newBillableRate,
|
||||
getOrganizationCurrencyString()
|
||||
getOrganizationCurrencyString(),
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
)
|
||||
: ' the default rate of the organization'
|
||||
}}</strong
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import type { Member } from '@/packages/api/src';
|
||||
import type { Member, Organization } from '@/packages/api/src';
|
||||
import { api } from '@/packages/api/src';
|
||||
import { CheckCircleIcon, UserCircleIcon } from '@heroicons/vue/20/solid';
|
||||
import MemberMoreOptionsDropdown from '@/Components/Common/Member/MemberMoreOptionsDropdown.vue';
|
||||
import TableRow from '@/Components/TableRow.vue';
|
||||
import { capitalizeFirstLetter } from '../../../utils/format';
|
||||
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
|
||||
import { api } from '@/packages/api/src';
|
||||
import { getCurrentOrganizationId } from '@/utils/useUser';
|
||||
import { useNotificationsStore } from '@/utils/notification';
|
||||
import { canInvitePlaceholderMembers } from '@/utils/permissions';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
import {computed, ref} from 'vue';
|
||||
import { computed, type ComputedRef, inject, ref } from 'vue';
|
||||
import MemberEditModal from '@/Components/Common/Member/MemberEditModal.vue';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
import MemberMergeModal from "@/Components/Common/Member/MemberMergeModal.vue";
|
||||
import MemberMakePlaceholderModal from "@/Components/Common/Member/MemberMakePlaceholderModal.vue";
|
||||
import MemberMergeModal from '@/Components/Common/Member/MemberMergeModal.vue';
|
||||
import MemberMakePlaceholderModal from '@/Components/Common/Member/MemberMakePlaceholderModal.vue';
|
||||
import { capitalizeFirstLetter } from '../../../utils/format';
|
||||
import { formatCents } from '../../../packages/ui/src/utils/money';
|
||||
|
||||
const props = defineProps<{
|
||||
member: Member;
|
||||
}>();
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
|
||||
const showEditMemberModal = ref(false);
|
||||
const showMergeMemberModal = ref(false);
|
||||
const showMakeMemberPlaceholderModal = ref(false);
|
||||
@@ -35,15 +36,12 @@ async function invitePlaceholder(id: string) {
|
||||
if (organizationId) {
|
||||
await handleApiRequestNotifications(
|
||||
() =>
|
||||
api.invitePlaceholder(
|
||||
undefined,
|
||||
{
|
||||
params: {
|
||||
organization: organizationId,
|
||||
member: id,
|
||||
},
|
||||
}
|
||||
),
|
||||
api.invitePlaceholder(undefined, {
|
||||
params: {
|
||||
organization: organizationId,
|
||||
member: id,
|
||||
},
|
||||
}),
|
||||
'Member invited successfully',
|
||||
'Error inviting member'
|
||||
);
|
||||
@@ -52,8 +50,7 @@ async function invitePlaceholder(id: string) {
|
||||
|
||||
const userHasValidMailAddress = computed(() => {
|
||||
return !props.member.email.endsWith('@solidtime-import.test');
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -75,7 +72,10 @@ const userHasValidMailAddress = computed(() => {
|
||||
member.billable_rate
|
||||
? formatCents(
|
||||
member.billable_rate,
|
||||
getOrganizationCurrencyString()
|
||||
organization?.currency,
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
)
|
||||
: '--'
|
||||
}}
|
||||
@@ -101,21 +101,26 @@ const userHasValidMailAddress = computed(() => {
|
||||
"
|
||||
size="small"
|
||||
@click="invitePlaceholder(member.id)"
|
||||
>Invite</SecondaryButton
|
||||
>
|
||||
>Invite
|
||||
</SecondaryButton>
|
||||
<MemberMoreOptionsDropdown
|
||||
:member="member"
|
||||
@edit="showEditMemberModal = true"
|
||||
@delete="removeMember"
|
||||
@merge="showMergeMemberModal = true"
|
||||
@make-placeholder="showMakeMemberPlaceholderModal = true"
|
||||
></MemberMoreOptionsDropdown>
|
||||
@make-placeholder="
|
||||
showMakeMemberPlaceholderModal = true
|
||||
"></MemberMoreOptionsDropdown>
|
||||
</div>
|
||||
<MemberEditModal
|
||||
v-model:show="showEditMemberModal"
|
||||
:member="member"></MemberEditModal>
|
||||
<MemberMergeModal v-model:show="showMergeMemberModal" :member="member"></MemberMergeModal>
|
||||
<MemberMakePlaceholderModal v-model:show="showMakeMemberPlaceholderModal" :member="member"></MemberMakePlaceholderModal>
|
||||
<MemberMergeModal
|
||||
v-model:show="showMergeMemberModal"
|
||||
:member="member"></MemberMergeModal>
|
||||
<MemberMakePlaceholderModal
|
||||
v-model:show="showMakeMemberPlaceholderModal"
|
||||
:member="member"></MemberMakePlaceholderModal>
|
||||
</TableRow>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import BillableRateModal from '@/packages/ui/src/BillableRateModal.vue';
|
||||
import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
import { inject, type ComputedRef } from 'vue';
|
||||
import type { Organization } from '@/packages/api/src';
|
||||
|
||||
const show = defineModel('show', { default: false });
|
||||
const saving = defineModel('saving', { default: false });
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
|
||||
defineProps<{
|
||||
newBillableRate?: number | null;
|
||||
}>();
|
||||
@@ -27,7 +31,10 @@ defineEmits<{
|
||||
newBillableRate
|
||||
? formatCents(
|
||||
newBillableRate,
|
||||
getOrganizationCurrencyString()
|
||||
getOrganizationCurrencyString(),
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
)
|
||||
: ' none.'
|
||||
}}</strong
|
||||
|
||||
@@ -47,12 +47,17 @@ function archiveProject() {
|
||||
});
|
||||
}
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
|
||||
const billableRateInfo = computed(() => {
|
||||
if (props.project.is_billable) {
|
||||
if (props.project.billable_rate) {
|
||||
return formatCents(
|
||||
props.project.billable_rate,
|
||||
getOrganizationCurrencyString()
|
||||
getOrganizationCurrencyString(),
|
||||
organization?.value?.currency_format,
|
||||
organization?.value?.currency_symbol,
|
||||
organization?.value?.number_format
|
||||
);
|
||||
} else {
|
||||
return 'Default Rate';
|
||||
@@ -63,7 +68,6 @@ const billableRateInfo = computed(() => {
|
||||
|
||||
const showEditProjectModal = ref(false);
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import BillableRateModal from '@/packages/ui/src/BillableRateModal.vue';
|
||||
import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
import { inject, type ComputedRef } from 'vue';
|
||||
import type { Organization } from '@/packages/api/src';
|
||||
|
||||
const show = defineModel('show', { default: false });
|
||||
const saving = defineModel('saving', { default: false });
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
|
||||
defineProps<{
|
||||
newBillableRate?: number | null;
|
||||
memberName?: string;
|
||||
@@ -28,7 +32,10 @@ defineEmits<{
|
||||
newBillableRate
|
||||
? formatCents(
|
||||
newBillableRate,
|
||||
getOrganizationCurrencyString()
|
||||
getOrganizationCurrencyString(),
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
)
|
||||
: ' the default rate of the project'
|
||||
}}</strong
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { ProjectMember } from '@/packages/api/src';
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, ref, inject, type ComputedRef } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import TableRow from '@/Components/TableRow.vue';
|
||||
import { useMembersStore } from '@/utils/useMembers';
|
||||
@@ -10,10 +10,14 @@ import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
import { capitalizeFirstLetter } from '@/utils/format';
|
||||
import ProjectMemberEditModal from '@/Components/Common/ProjectMember/ProjectMemberEditModal.vue';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import type { Organization } from '@/packages/api/src';
|
||||
|
||||
const props = defineProps<{
|
||||
projectMember: ProjectMember;
|
||||
}>();
|
||||
|
||||
const organization = inject<ComputedRef<Organization>>('organization');
|
||||
|
||||
function deleteProjectMember() {
|
||||
useProjectMembersStore().deleteProjectMember(
|
||||
props.projectMember.project_id,
|
||||
@@ -51,7 +55,10 @@ const showEditModal = ref(false);
|
||||
projectMember.billable_rate
|
||||
? formatCents(
|
||||
projectMember.billable_rate,
|
||||
getOrganizationCurrencyString()
|
||||
getOrganizationCurrencyString(),
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
)
|
||||
: '--'
|
||||
}}
|
||||
|
||||
@@ -8,7 +8,11 @@ import {
|
||||
import { FolderIcon } from '@heroicons/vue/16/solid';
|
||||
import BillableIcon from '@/packages/ui/src/Icons/BillableIcon.vue';
|
||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||
import { formatHumanReadableDuration } from '@/packages/ui/src/utils/time';
|
||||
import {
|
||||
formatHumanReadableDuration,
|
||||
getDayJsInstance,
|
||||
getLocalizedDayJs,
|
||||
} from '@/packages/ui/src/utils/time';
|
||||
import { formatCents } from '@/packages/ui/src/utils/money';
|
||||
import ReportingTabNavbar from '@/Components/Common/Reporting/ReportingTabNavbar.vue';
|
||||
import ReportingExportButton from '@/Components/Common/Reporting/ReportingExportButton.vue';
|
||||
@@ -29,17 +33,13 @@ import ReportSaveButton from '@/Components/Common/Report/ReportSaveButton.vue';
|
||||
import TagDropdown from '@/packages/ui/src/Tag/TagDropdown.vue';
|
||||
import ReportingPieChart from '@/Components/Common/Reporting/ReportingPieChart.vue';
|
||||
|
||||
import { computed, onMounted, ref, inject, type ComputedRef } from 'vue';
|
||||
import {
|
||||
getDayJsInstance,
|
||||
getLocalizedDayJs,
|
||||
} from '@/packages/ui/src/utils/time';
|
||||
import { computed, type ComputedRef, inject, onMounted, ref } from 'vue';
|
||||
import { type GroupingOption, useReportingStore } from '@/utils/useReporting';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import {
|
||||
type AggregatedTimeEntriesQueryParams,
|
||||
type CreateReportBodyProperties,
|
||||
api,
|
||||
type CreateReportBodyProperties,
|
||||
type Organization,
|
||||
} from '@/packages/api/src';
|
||||
import {
|
||||
@@ -52,6 +52,7 @@ import { useSessionStorage, useStorage } from '@vueuse/core';
|
||||
import { useNotificationsStore } from '@/utils/notification';
|
||||
import type { ExportFormat } from '@/types/reporting';
|
||||
import { getRandomColorWithSeed } from '@/packages/ui/src/utils/color';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
|
||||
const { handleApiRequestNotifications } = useNotificationsStore();
|
||||
|
||||
@@ -213,7 +214,6 @@ async function downloadExport(format: ExportFormat) {
|
||||
}
|
||||
|
||||
const { getNameForReportingRowEntry, emptyPlaceholder } = useReportingStore();
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
|
||||
const projectsStore = useProjectsStore();
|
||||
const { projects } = storeToRefs(projectsStore);
|
||||
@@ -450,10 +450,8 @@ const tableData = computed(() => {
|
||||
v-for="entry in tableData"
|
||||
:key="entry.description ?? 'none'"
|
||||
:currency="getOrganizationCurrencyString()"
|
||||
:entry="entry"
|
||||
:type="
|
||||
aggregatedTableTimeEntries.grouped_type
|
||||
"></ReportingRow>
|
||||
:type="aggregatedTableTimeEntries.grouped_type"
|
||||
:entry="entry"></ReportingRow>
|
||||
<div
|
||||
class="contents [&>*]:transition text-text-tertiary [&>*]:h-[50px]">
|
||||
<div class="flex items-center pl-6 font-medium">
|
||||
@@ -475,7 +473,10 @@ const tableData = computed(() => {
|
||||
aggregatedTableTimeEntries.cost
|
||||
? formatCents(
|
||||
aggregatedTableTimeEntries.cost,
|
||||
getOrganizationCurrencyString()
|
||||
getOrganizationCurrencyString(),
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
)
|
||||
: '--'
|
||||
}}
|
||||
|
||||
@@ -57,7 +57,13 @@ const organization = inject<ComputedRef<Organization>>('organization');
|
||||
}}
|
||||
</div>
|
||||
<div class="justify-end pr-6 flex items-center">
|
||||
{{ entry.cost ? formatCents(entry.cost, props.currency) : '--' }}
|
||||
{{ entry.cost ? formatCents(
|
||||
entry.cost,
|
||||
props.currency,
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
) : '--' }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
title: string;
|
||||
value: string;
|
||||
value?: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
@@ -10,7 +10,7 @@ defineProps<{
|
||||
class="rounded-lg bg-card-background border-card-border shadow-card border px-3.5 py-2.5">
|
||||
<dt class="font-semibold text-sm text-text-secondary">{{ title }}</dt>
|
||||
<dd class="text-2xl text-text-primary pt-1 font-semibold">
|
||||
{{ value }}
|
||||
{{ value ?? '--' }}
|
||||
</dd>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -283,7 +283,10 @@ const option = computed(() => {
|
||||
totalWeeklyBillableAmount
|
||||
? formatCents(
|
||||
totalWeeklyBillableAmount.value,
|
||||
getOrganizationCurrencyString()
|
||||
getOrganizationCurrencyString(),
|
||||
organization?.currency_format,
|
||||
organization?.currency_symbol,
|
||||
organization?.number_format
|
||||
)
|
||||
: '--'
|
||||
" />
|
||||
|
||||
Reference in New Issue
Block a user