Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ tools:
title: Percentage calculator
description: Easily calculate percentages from a value to another value, or from a percentage to a value.

tip-calculator:
title: Tip calculator
description: Calculate the tip for a bill and split it among multiple people.

svg-placeholder-generator:
title: SVG placeholder generator
description: Generate svg images to use as a placeholder in your applications.
Expand Down
3 changes: 2 additions & 1 deletion src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { tool as dateTimeConverter } from './date-time-converter';
import { tool as deviceInformation } from './device-information';
import { tool as cypher } from './encryption';
import { tool as etaCalculator } from './eta-calculator';
import { tool as tipCalculator } from './tip-calculator';
import { tool as percentageCalculator } from './percentage-calculator';
import { tool as gitMemo } from './git-memo';
import { tool as hashText } from './hash-text';
Expand Down Expand Up @@ -168,7 +169,7 @@ export const toolsByCategory: ToolCategory[] = [
},
{
name: 'Math',
components: [mathEvaluator, etaCalculator, percentageCalculator],
components: [mathEvaluator, etaCalculator, percentageCalculator, tipCalculator],
},
{
name: 'Measurement',
Expand Down
13 changes: 13 additions & 0 deletions src/tools/tip-calculator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Calculator } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';

export const tool = defineTool({
name: translate('tools.tip-calculator.title'),
path: '/tip-calculator',
description: translate('tools.tip-calculator.description'),
keywords: ['tip', 'calculator', 'bill', 'split', 'restaurant', 'money', 'payment'],
component: () => import('./tip-calculator.vue'),
icon: Calculator,
createdAt: new Date('2024-04-17'),
});
49 changes: 49 additions & 0 deletions src/tools/tip-calculator/tip-calculator.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { expect, test } from '@playwright/test';

test.describe('Tool - Tip calculator', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/tip-calculator');
});

test('Has correct title', async ({ page }) => {
await expect(page).toHaveTitle('Tip calculator - IT Tools');
});

test('Correctly calculates tip and split', async ({ page }) => {
// Fill bill amount
await page.getByTestId('billAmount').locator('input').fill('100');

Check failure on line 15 in src/tools/tip-calculator/tip-calculator.e2e.spec.ts

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
// Fill tip percentage
await page.getByTestId('tipPercentage').locator('input').fill('15');

Check failure on line 18 in src/tools/tip-calculator/tip-calculator.e2e.spec.ts

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
// Fill number of people
await page.getByTestId('numberOfPeople').locator('input').fill('2');

// Check results
// 100 * 0.15 = 15.00
await expect(page.getByTestId('tipAmountResult').locator('input')).toHaveValue('15.00');

Check failure on line 25 in src/tools/tip-calculator/tip-calculator.e2e.spec.ts

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
// 100 + 15 = 115.00
await expect(page.getByTestId('totalBillResult').locator('input')).toHaveValue('115.00');

Check failure on line 28 in src/tools/tip-calculator/tip-calculator.e2e.spec.ts

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
// 115 / 2 = 57.50
await expect(page.getByTestId('amountPerPersonResult').locator('input')).toHaveValue('57.50');
});

test('Quick tip buttons work', async ({ page }) => {
await page.getByTestId('billAmount').locator('input').fill('100');

Check failure on line 35 in src/tools/tip-calculator/tip-calculator.e2e.spec.ts

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
// Click 20% button
await page.getByRole('button', { name: '20%' }).click();

Check failure on line 38 in src/tools/tip-calculator/tip-calculator.e2e.spec.ts

View workflow job for this annotation

GitHub Actions / ci

Trailing spaces not allowed
await expect(page.getByTestId('tipPercentage').locator('input')).toHaveValue('20');
await expect(page.getByTestId('tipAmountResult').locator('input')).toHaveValue('20.00');
});

test('Displays initial/empty results correctly', async ({ page }) => {
// Initial state with empty bill
await expect(page.getByTestId('tipAmountResult').locator('input')).toHaveValue('0.00');
await expect(page.getByTestId('totalBillResult').locator('input')).toHaveValue('0.00');
await expect(page.getByTestId('amountPerPersonResult').locator('input')).toHaveValue('0.00');
});
});
69 changes: 69 additions & 0 deletions src/tools/tip-calculator/tip-calculator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<script setup lang="ts">
const billAmount = ref<number>();
const tipPercentage = ref<number>(15);
const numberOfPeople = ref<number>(1);

const tipAmount = computed(() => (billAmount.value && tipPercentage.value) ? (billAmount.value * tipPercentage.value) / 100 : 0);
const totalAmount = computed(() => billAmount.value ? billAmount.value + tipAmount.value : 0);
const amountPerPerson = computed(() => (totalAmount.value && numberOfPeople.value && numberOfPeople.value > 0) ? totalAmount.value / numberOfPeople.value : 0);

const formatNum = (v: number) => new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(v);

const results = computed(() => [
{ label: 'Tip Amount', val: formatNum(tipAmount.value), id: 'tipAmountResult' },
{ label: 'Total Bill', val: formatNum(totalAmount.value), id: 'totalBillResult' },
{ label: 'Amount Per Person', val: formatNum(amountPerPerson.value), id: 'amountPerPersonResult', isBold: true }

Check failure on line 15 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Missing trailing comma
]);
</script>

<template>
<div style="flex: 0 0 100%">
<div style="margin: 0 auto; max-width: 600px">
<c-card mb-3>
<div mb-3>Bill details</div>

Check warning on line 23 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break before closing tag (`</div>`), but no line breaks found

Check warning on line 23 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break after opening tag (`<div>`), but no line breaks found
<div flex flex-col gap-4>
<div flex items-center gap-2>
<div style="min-width: 120px;">Bill Amount</div>

Check warning on line 26 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break before closing tag (`</div>`), but no line breaks found

Check warning on line 26 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break after opening tag (`<div>`), but no line breaks found
<div style="flex: 1" data-test-id="billAmount">
<n-input-number v-model:value="billAmount" :min="0" placeholder="Total Bill" />
</div>
</div>
<div flex items-center gap-2>
<div style="min-width: 120px;">Tip Percentage</div>

Check warning on line 32 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break before closing tag (`</div>`), but no line breaks found

Check warning on line 32 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break after opening tag (`<div>`), but no line breaks found
<div style="flex: 1" data-test-id="tipPercentage">
<n-input-number v-model:value="tipPercentage" :min="0" placeholder="Tip %">
<template #suffix>%</template>

Check warning on line 35 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break before closing tag (`</template>`), but no line breaks found

Check warning on line 35 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break after opening tag (`<template>`), but no line breaks found
</n-input-number>
</div>
</div>
<div flex items-center gap-2>
<div style="min-width: 120px;">Number of People</div>

Check warning on line 40 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Expected 1 line break after opening tag (`<div>`), but no line breaks found
<div style="flex: 1" data-test-id="numberOfPeople">
<n-input-number v-model:value="numberOfPeople" :min="1" placeholder="People" />
</div>
</div>
</div>
</c-card>

<c-card mb-3>
<div mb-3>Results</div>
<div flex flex-col gap-3>
<div v-for="res in results" :key="res.id" flex justify-between items-center :class="{'border-t pt-3 font-bold': res.isBold}">

Check failure on line 51 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

A space is required before '}'

Check failure on line 51 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

A space is required after '{'
<span>{{ res.label }}:</span>
<div :data-test-id="res.id" style="max-width: 200px; width: 100%;">
<input-copyable :value="res.val" readonly />
</div>
</div>
</div>
</c-card>

<c-card>
<div mb-2>Quick Tip %</div>
<div flex gap-2>
<n-button v-for="tip in [10, 15, 18, 20, 25]" :key="tip" @click="tipPercentage = tip" size="small">{{ tip }}%</n-button>
</div>
</c-card>
</div>
</div>
</template>

Check failure on line 69 in src/tools/tip-calculator/tip-calculator.vue

View workflow job for this annotation

GitHub Actions / ci

Too many blank lines at the end of file. Max of 0 allowed
Loading