Skip to content

Commit 2a6e583

Browse files
feat: add Tip Calculator and Bill Splitter tool
"Tip Calculator & Bill Splitter" tool to the Maths category. It allows users to calculate gratuity and split bills among multiple people with a clean, responsive UI. Closes CorentinTh#1778 Co-authored-by: ShareVB <sharevb@gmail.com>
1 parent 4178707 commit 2a6e583

3 files changed

Lines changed: 91 additions & 0 deletions

File tree

locales/en.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ tools:
162162
tag-x-is-what-percent-of-y: X is what percent of Y
163163
tag-is-what-percent-of: is what percent of
164164
tag-what-is-the-percentage-increase-decrease: What is the percentage increase/decrease
165+
166+
tip-calculator:
167+
title: Tip calculator
168+
description: Calculate the tip for a bill and split it among multiple people.
169+
165170
svg-placeholder-generator:
166171
title: SVG placeholder generator
167172
description: Generate svg images to use as a placeholder in your applications.

src/tools/tip-calculator/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Calculator } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
import { translate as t } from '@/plugins/i18n.plugin';
4+
5+
export const tool = defineTool({
6+
name: t('tools.tip-calculator.title'),
7+
path: '/tip-calculator',
8+
description: t('tools.tip-calculator.description'),
9+
keywords: ['tip', 'calculator', 'bill', 'split', 'restaurant', 'money', 'payment'],
10+
component: () => import('./tip-calculator.vue'),
11+
icon: Calculator,
12+
createdAt: new Date('2024-04-17'),
13+
category: 'Maths',
14+
});
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<script setup lang="ts">
2+
const billAmount = ref<number>();
3+
const tipPercentage = ref<number>(15);
4+
const numberOfPeople = ref<number>(1);
5+
6+
const tipAmount = computed(() => {
7+
if (billAmount.value === undefined || tipPercentage.value === undefined) {
8+
return 0;
9+
}
10+
return (billAmount.value * tipPercentage.value) / 100;
11+
});
12+
13+
const totalAmount = computed(() => {
14+
if (billAmount.value === undefined) {
15+
return 0;
16+
}
17+
return billAmount.value + tipAmount.value;
18+
});
19+
20+
const amountPerPerson = computed(() => {
21+
if (totalAmount.value === 0 || numberOfPeople.value === undefined || numberOfPeople.value <= 0) {
22+
return 0;
23+
}
24+
return totalAmount.value / numberOfPeople.value;
25+
});
26+
27+
function formatCurrency(value: number) {
28+
return new Intl.NumberFormat().format(value);
29+
}
30+
31+
const tipAmountFormatted = computed(() => formatCurrency(tipAmount.value));
32+
const totalAmountFormatted = computed(() => formatCurrency(totalAmount.value));
33+
const amountPerPersonFormatted = computed(() => formatCurrency(amountPerPerson.value));
34+
</script>
35+
36+
<template>
37+
<div style="margin: 0 auto; max-width: 600px">
38+
<c-card mb-3 title="Bill Details">
39+
<n-form label-placement="left" label-width="150px" label-align="left">
40+
<n-form-item label="Bill Amount:">
41+
<n-input-number v-model:value="billAmount" :min="0" placeholder="Total Bill" />
42+
</n-form-item>
43+
44+
<n-form-item label="Tip Percentage:">
45+
<n-input-number v-model:value="tipPercentage" :min="0" placeholder="Tip %">
46+
<template #suffix>
47+
%
48+
</template>
49+
</n-input-number>
50+
</n-form-item>
51+
52+
<n-form-item label="Number of person:">
53+
<n-input-number v-model:value="numberOfPeople" :min="1" placeholder="People" />
54+
</n-form-item>
55+
</n-form>
56+
</c-card>
57+
58+
<c-card mb-3 title="Results">
59+
<input-copyable label="Tip Amount:" :value="tipAmountFormatted" readonly label-position="left" label-width="150px" mb-1 />
60+
<input-copyable label="Total Bill:" :value="totalAmountFormatted" readonly label-position="left" label-width="150px" mb-1 />
61+
<input-copyable label="Amount Per Person:" :value="amountPerPersonFormatted" readonly label-position="left" label-width="150px" mb-1 />
62+
</c-card>
63+
64+
<c-card title="Quick Tip %">
65+
<n-space justify="center">
66+
<n-button v-for="tip in [10, 15, 18, 20, 25]" :key="tip" size="small" @click="tipPercentage = tip">
67+
{{ tip }}%
68+
</n-button>
69+
</n-space>
70+
</c-card>
71+
</div>
72+
</template>

0 commit comments

Comments
 (0)