122 lines
4 KiB
Vue
122 lines
4 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
import axios from 'axios';
|
|
import { useToast } from 'vue-toast-notification';
|
|
import Button from '@scripts/app/components/Button.vue';
|
|
import Input from '@scripts/app/components/Input.vue';
|
|
|
|
const $toast = useToast();
|
|
|
|
const subnet = ref( '' );
|
|
const isLoading = ref( false );
|
|
const hasResults = ref( false );
|
|
const results = ref( {} );
|
|
|
|
/**
|
|
* Load subnet data based on input
|
|
*/
|
|
const getSubnetData = async (): void => {
|
|
// Check if subnet is filled
|
|
if (subnet.value === '') {
|
|
errorMsg('Subnet is required');
|
|
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Enable loading state
|
|
isLoading.value = true;
|
|
|
|
// Prepare request payload
|
|
const postData = new FormData();
|
|
postData.append( 'subnet', subnet.value );
|
|
|
|
// Send request and handle response
|
|
const response = await axios.post( '/api/subnet', postData );
|
|
const { data } = response;
|
|
|
|
// Update results and UI state
|
|
results.value = data.result;
|
|
hasResults.value = true;
|
|
} catch (error) {
|
|
// Extract and show error message
|
|
const errorMessage = error.response?.data?.message || 'Something went wrong.';
|
|
errorMsg(errorMessage);
|
|
} finally {
|
|
// Reset loading state
|
|
isLoading.value = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset form by resetting al vars
|
|
*/
|
|
const resetForm = (): void => {
|
|
subnet.value = '';
|
|
isLoading.value = false;
|
|
hasResults.value = false;
|
|
results.value = {};
|
|
}
|
|
|
|
/**
|
|
* Send error message
|
|
*
|
|
* @param message
|
|
*/
|
|
const errorMsg = (message: string): void => {
|
|
$toast.error(message, {
|
|
position: 'top',
|
|
duration: 1500,
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex justify-center items-center min-h-screen">
|
|
<div class="sm:w-3/4 md:w-2/3 lg:w-2/4 xl:w-2/5 2xl:w-1/5 -translate-y-24">
|
|
<img src="https://www.bit.nl/assets/images/bit_logo_white.png" alt="BIT Logo" class="mx-auto w-52 mb-6">
|
|
|
|
<div class="bg-white p-10 rounded-xl shadow-2xl">
|
|
<h1 class="text-2xl font-semibold text-center mb-6">IPcalc-u-later</h1>
|
|
|
|
<div v-if="hasResults">
|
|
<table class="min-w-full table-auto text-left">
|
|
<tbody>
|
|
<tr class="">
|
|
<td class="py-2 font-medium">Network Address</td>
|
|
<td class="py-2 text-right">{{ results.network }}</td>
|
|
</tr>
|
|
<tr class="">
|
|
<td class="py-2 font-medium">First Usable IP</td>
|
|
<td class="py-2 text-right">{{ results.first }}</td>
|
|
</tr>
|
|
<tr class="">
|
|
<td class="py-2 font-medium">Last Usable IP</td>
|
|
<td class="py-2 text-right">{{ results.last }}</td>
|
|
</tr>
|
|
<tr class="">
|
|
<td class="py-2 font-medium">Number of Usable Hosts</td>
|
|
<td class="py-2 text-right">{{ results.hosts }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<Button @click="resetForm">Reset</Button>
|
|
</div>
|
|
|
|
<form v-else method="post" class="text-left" @submit.prevent="getSubnetData">
|
|
<div class="mb-4">
|
|
<label for="subnet" class="block text-sm font-medium">Enter Subnet</label>
|
|
|
|
<Input name="subnet" v-model="subnet" placeholder="(e.g. 192.168.1.0/24 or 2001:db8::/64)" />
|
|
</div>
|
|
|
|
<Button type="submit">
|
|
<i class="fa-solid fa-circle-notch fa-pulse" v-if="isLoading"></i>
|
|
<span v-else>Submit</span>
|
|
</Button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|