Added connection error message, added max height for tags field, added optional google maps link, added price options.

main
Eloi Zalczer 2024-06-19 17:31:04 +02:00
parent 04fb307b7a
commit d73cb4dbb8
7 changed files with 59 additions and 15 deletions

View File

@ -18,6 +18,10 @@ const { errors, handleSubmit, defineField, resetForm } = useForm({
name: yup.string().required("This field is required."),
tags: yup.array().of(yup.string()),
price: yup.string().required("This field is required."),
googleMapsLink: yup
.string()
.trim()
.matches(/^$|https:\/\/maps\.app\.goo\.gl\/[a-zA-Z0-9]+/, "Not a valid Google Maps link."),
})
),
});
@ -39,6 +43,7 @@ const submit = handleSubmit((values) => {
tags: tags,
latitude: position.value?.lat,
longitude: position.value?.lng,
googleMapsLink: values.googleMapsLink,
});
emit("succeeded", `Restaurant ${values.name} created successfully!`);
@ -65,6 +70,7 @@ onMounted(async () => {
const [name, nameAttrs] = defineField("name");
const [tags, tagsAttrs] = defineField("tags");
const [price, priceAttrs] = defineField("price");
const [googleMapsLink, googleMapsLinkAttrs] = defineField("googleMapsLink");
const emit = defineEmits({
succeeded: (message: string) => true,
@ -138,12 +144,25 @@ defineExpose({ show, hide, setRestaurantPosition });
v-bind="priceAttrs"
>
<option value="€">1-10</option>
<option value="€€">10-20</option>
<option value="€€€">20-30</option>
<option value="€€">10-15</option>
<option value="€€€">15-20</option>
<option value="€€€€">>20</option>
</select>
<label class="text-red-500">{{ errors.price }}</label>
</div>
</div>
<div class="flex flex-row flex-nowrap w-96">
<div class="mx-5 my-4 w-full">
<label class="form-label"> Google Maps Link (Optional) </label>
<input
:class="errors.googleMapsLink === undefined ? 'form-field' : 'form-field-error'"
v-model="googleMapsLink"
v-bind="googleMapsLinkAttrs"
type="text"
/>
<label class="text-red-500">{{ errors.googleMapsLink }}</label>
</div>
</div>
</div>
</ModalComponent>
</template>

View File

@ -23,6 +23,7 @@ const columns = [
_: "[, ]",
},
},
{ data: "price", title: "Price" },
{ data: "average_rating", title: "" },
];
@ -39,7 +40,7 @@ function deselectAll() {
}
const emit = defineEmits({
restaurantSelected: (restaurant: Object) => true,
restaurantSelected: (restaurant: Restaurant) => true,
restaurantHovered: (restaurant: Object | null) => true,
});
@ -92,7 +93,7 @@ defineExpose({ deselectAll });
}"
@select="onRowSelected"
>
<template #column-2="props">
<template #column-3="props">
<RatingField
v-if="props.cellData !== null"
:disabled="true"

View File

@ -3,9 +3,10 @@ import { ref } from "vue";
import ReviewsList from "./ReviewsList.vue";
import ReviewField from "./ReviewField.vue";
import { currentUser, pb } from "../pocketbase";
import Restaurant from "../models/restaurant";
const props = defineProps({
restaurant: { type: Object },
restaurant: { type: Object as () => Restaurant },
});
const opened = ref<boolean>(false);
@ -49,11 +50,22 @@ defineExpose({ open, close });
<div class="drawer-side w-full">
<label @click.prevent="close" for="my-drawer" aria-label="close sidebar" class="drawer-overlay"></label>
<div class="menu p-4 space-y-4 w-full lg:w-2/6 min-h-full bg-base-200 text-base-content">
<font-awesome-icon
@click="close"
class="btn btn-circle btn-sm text-gray-500 bg-transparent"
icon="fa-solid fa-xmark"
/>
<div class="flex flex-row w-full">
<font-awesome-icon
@click="close"
class="btn btn-circle btn-sm text-gray-500 bg-transparent"
icon="fa-solid fa-xmark"
/>
<div class="flex-1"></div>
<a
v-if="props.restaurant?.googleMapsLink"
:href="props.restaurant.googleMapsLink"
class="btn btn-ghost btn-link btn-sm"
target="_blank"
rel="noopener noreferrer"
>View on Google Maps</a
>
</div>
<ReviewField ref="reviewField" @publish="onPublishReview" />
<ReviewsList ref="reviewsList" :restaurant="props.restaurant" />

View File

@ -85,7 +85,9 @@ function filteredOptions() {
<font-awesome-icon icon="xmark" />
</button>
</div>
<ul class="menu dropdown-content z-10 w-full rounded-lg border border-neutral-content bg-base-100 p-0 shadow">
<ul
class="menu flex-nowrap dropdown-content overflow-y-auto z-10 max-h-96 w-full rounded-lg border border-neutral-content bg-base-100 p-0 shadow"
>
<li><button @click="onCreateNewTag">Create new tag...</button></li>
<li v-for="option in filteredOptions()" :key="option" role="option" class="m-0 p-0">
<button :class="{ active: model?.includes(option) }" @click="onOptionClicked(option)">

View File

@ -6,4 +6,5 @@ export default interface Restaurant {
averageRating: number;
latitude: number;
longitude: number;
googleMapsLink?: string;
}

View File

@ -5,16 +5,17 @@ import RestaurantsMap from "../components/RestaurantsMap.vue";
import ReviewsDrawer from "../components/ReviewsDrawer.vue";
import { storeToRefs } from "pinia";
import { useRestaurantsStore } from "../stores/restaurants";
import Restaurant from "../models/restaurant";
const drawer = ref<typeof ReviewsDrawer>();
const table = ref<typeof RestaurantsTable>();
const selectedRestaurant = ref<Object>();
const selectedRestaurant = ref<Restaurant>();
const highlightedRestaurant = ref<string>();
const { restaurants } = storeToRefs(useRestaurantsStore());
function onRestaurantSelected(restaurant: Object) {
function onRestaurantSelected(restaurant: Restaurant) {
selectedRestaurant.value = restaurant;
drawer.value?.open();
}

View File

@ -10,12 +10,18 @@ const valid = computed(() => {
return username.value !== undefined && password.value !== undefined;
});
const errorMessage = ref<string>();
async function login() {
if (!valid.value) {
return;
}
await pb.collection("users").authWithPassword(username.value!, password.value!);
try {
await pb.collection("users").authWithPassword(username.value!, password.value!);
} catch (err) {
errorMessage.value = "Incorrect username or password.";
}
}
</script>
@ -35,7 +41,9 @@ async function login() {
</div>
</div>
<button @click="login" :disabled="!valid">Log In</button>
<label v-if="errorMessage" class="text-red-500">{{ errorMessage }}</label>
<button @click="login" :disabled="!valid" class="my-3 btn btn-outline">Log In</button>
<p>New to DOXFOOD ? <RouterLink to="/signup">Create an account !</RouterLink></p>
</form>
</template>