Initial commit

This commit is contained in:
Stedoss
2023-12-07 00:20:59 +00:00
commit 284a36412d
66 changed files with 7591 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { Auth } from '../../connectors/auth.connector';
import router from '../../router';
const email = ref('');
const password = ref('');
const loginFailure = ref<boolean>(false);
async function login() {
const success = await Auth.Login(email.value, password.value);
if (success) {
router.push('/search');
return;
}
loginFailure.value = true;
}
</script>
<template>
<v-form @submit.prevent="login">
<v-card
class="mx-auto pa-12 pb-8"
elevation="8"
max-width="448"
rounded="lg"
>
<div class="text-subtitle-1 text-medium-emphasis">Account</div>
<v-text-field
density="compact"
placeholder="Email address"
prepend-inner-icon="mdi-email-outline"
variant="outlined"
v-model="email"
:error="loginFailure"
@update:model-value="() => loginFailure = false"
></v-text-field>
<div class="text-subtitle-1 text-medium-emphasis d-flex align-center justify-space-between">
Password
</div>
<v-text-field
type="password"
density="compact"
placeholder="Enter your password"
prepend-inner-icon="mdi-lock-outline"
variant="outlined"
v-model="password"
:error="loginFailure"
@update:model-value="() => loginFailure = false"
></v-text-field>
<v-label
v-if="loginFailure"
class="text-red">
Login failed, please try again.
</v-label>
<v-btn
block
class="mb-8"
color="blue"
size="large"
variant="tonal"
type="submit"
>
Log In
</v-btn>
<v-card-text class="text-center">
<a
class="text-blue text-decoration-none"
href="/register"
rel="noopener noreferrer"
>
Sign up now <v-icon icon="mdi-chevron-right"></v-icon>
</a>
</v-card-text>
</v-card>
</v-form>
</template>

View File

@@ -0,0 +1,90 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { Auth } from '../../connectors/auth.connector';
import router from '../../router';
const email = ref('');
const password = ref('');
const confirmPassword = ref('');
const errors = ref<string[]>([]);
async function register() {
if (password.value !== confirmPassword.value) {
return;
}
const result = await Auth.Register(email.value, password.value);
if (result.success) {
router.push('/login');
return;
}
errors.value = Object.values(result.errors ?? []).flat();
}
</script>
<template>
<v-form @submit.prevent="register">
<v-card
class="mx-auto pa-12 pb-8"
elevation="8"
max-width="448"
rounded="lg"
>
<div class="text-subtitle-1 text-medium-emphasis">Account</div>
<v-text-field
density="compact"
placeholder="Email address"
prepend-inner-icon="mdi-email-outline"
variant="outlined"
v-model="email"
:error="errors.length > 0"
></v-text-field>
<div class="text-subtitle-1 text-medium-emphasis d-flex align-center justify-space-between">
Password
</div>
<v-text-field
type="password"
density="compact"
placeholder="Enter your password"
prepend-inner-icon="mdi-lock-outline"
variant="outlined"
v-model="password"
:error="errors.length > 0"
></v-text-field>
<v-text-field
type="password"
density="compact"
placeholder="Re-Enter your password"
prepend-inner-icon="mdi-lock-outline"
variant="outlined"
v-model="confirmPassword"
:error="errors.length > 0"
></v-text-field>
<v-label
v-if="errors"
class="text-red">
{{ errors.join('\n') }}
</v-label>
<v-btn
block
class="mb-8"
color="blue"
size="large"
variant="tonal"
type="submit"
>
Sign Up
</v-btn>
</v-card>
</v-form>
</template>

View File

@@ -0,0 +1,30 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
import { Debounce } from '@/utils/debounce';
type Emits = {
(e: 'onSearch', value: string): void,
};
const emit = defineEmits<Emits>();
const searchContent = ref('');
const debounce = new Debounce();
watch(searchContent, () => debounce.debounce(() => emit('onSearch', searchContent.value), 200));
</script>
<template>
<v-text-field
variant="solo"
label="Search beer"
append-inner-icon="mdi-magnify"
single-line
hide-details
v-model="searchContent"
/>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,33 @@
<script lang="ts" setup>
import SearchField from '@/components/Inputs/SearchField.vue';
import { ref } from 'vue';
import { searchBeer } from '@/connectors/punk.connector';
import SearchTable from '@/components/Tables/SearchTable.vue';
import { useQuery } from '@tanstack/vue-query';
const searchValue = ref<string>('');
const { isLoading, error, data } = useQuery({
queryKey: ['search', searchValue],
queryFn: async () => {
if (!searchValue.value) {
return [];
}
return await searchBeer(searchValue.value)
},
});
</script>
<template>
<v-container class="fill-height">
<v-responsive class="align-center text-center fill-height">
<search-field @on-search="async (value: string) => searchValue = value" />
<search-table
:beers="data ?? []"
:error="error?.message"
:loading="isLoading"
/>
</v-responsive>
</v-container>
</template>

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import { Beer } from '@/models/Beer';
type Props = {
beers: Beer[],
loading: boolean,
error?: string,
};
const { beers } = defineProps<Props>();
</script>
<template>
<h1>Favourites</h1>
<p v-if="loading">Loading...</p>
<p v-else-if="error">An error has occurred, please try refreshing the page.</p>
<v-table v-else>
<thead class="text-center">
<tr>
<th>
ID
</th>
<th>
NAME
</th>
</tr>
</thead>
<tbody>
<tr
v-for="beer in beers"
:key="beer.id">
<td>{{ beer.id }}</td>
<td>{{ beer.name }}</td>
</tr>
</tbody>
</v-table>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,57 @@
<script setup lang="ts">
import { Beer } from '@/models/Beer';
import { addFavouriteBeer } from '../../connectors/punk.connector';
import { ref } from 'vue';
type Props = {
beers: Beer[],
loading: boolean,
error?: string,
};
const snackbar = ref(false);
const snackbarText = ref('');
const { beers } = defineProps<Props>();
</script>
<template>
<v-snackbar
v-model="snackbar"
>
{{ snackbarText }}
</v-snackbar>
<p v-if="loading">Loading...</p>
<p v-else-if="error">An error has occurred. {{ error }}</p>
<div
v-else
@click="async () => {
const result = await addFavouriteBeer(beer.id);
snackbar = true;
snackbarText = result ? `Added ${beer.name} to favourites!` : 'An error occurred whilst trying to add a favourite.';
}"
class="mt-2 mb-4 entry rounded-xl"
v-for="beer in beers"
:key="beer.id">
<p>
{{ beer.name }} -
{{ beer.id }}
</p>
{{ beer.tagline }}
{{ beer.first_brewed }}
{{ beer.description }}
{{ beer.image_url }}
{{ beer.abv }}
{{ beer.iby }}
{{ beer.food_pairing?.join(',') }}
</div>
</template>
<style scoped>
.entry {
background-color:azure;
cursor: pointer;
}
</style>