I have captcha in ajax form.
captcha is reloaded after each successfull POST request this.mathcaptchaLabel = response.data.mathcaptchaLabel;
captcha can be reloaded by click on the button <x-modules.button icon="refresh" style="black-outline" class="px-4" #click.prevent="mathcaptchaReset()" />
But I cannot understand how to make captcha reload in case of captcha validation error.
I tried to play with isErrorCaptcha() inside .catch( (error), but it doesn't work.
For example when there is no error, then errorData object doesn't have mathcaptcha array. So I suppose that error.response.data.errors.mathcaptcha should be undefined.
And when there is captcha error I expect error.response.data.errors.mathcaptcha !== 'undefined' and this.errorStates.mathcaptcha = true.
But in console I see
Uncaught (in promise) ReferenceError: error is not defined
at Proxy.isErrorName
And in AlpineJS devtools errorStates.mathcaptcha is false, though in devtools I see that mathcaptcha array exists in errorData object.
blade view
<form method="POST" action="/modalform" method="POST" #submit.prevent="submitData()">
#csrf
<div class="bg-white">
<div class="modalheader flex place-items-center text-center border-b cursor-pointer text-lg leading-6 font-medium text-gray-900">
<h3 class="p-2 hover:bg-blue-500 hover:text-white"
#click="$dispatch('callback')"
:class="callback ? 'bg-blue-500 text-white' : ''"
>
Перезвоните мне
</h3>
<h3 class="p-2 hover:bg-blue-500 hover:text-white"
#click="$dispatch('zamer')"
:class="zamer ? 'bg-blue-500 text-white' : ''"
>
Записаться на замер
</h3>
<h3 class="p-2 hover:bg-blue-500 hover:text-white"
#click="$dispatch('eskiz')"
:class="eskiz ? 'bg-blue-500 text-white' : ''"
>
Отправить эскиз
</h3>
<div class="p-2 place-self-stretch hover:bg-blue-500 hover:text-white" #click="closeModal()" >
<span class="text-3xl">×</span>
</div>
</div>
<div class="modalbody flex items-center w-full h-full p-5"
x-show="sent"
x-text="message"
x-transition:enter="transition ease-out duration-500"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 "
x-transition:leave-end="opacity-0 "
>
</div>
<div class="modalbody flex items-start flex-wrap p-5"
x-show="!sent"
x-transition:enter="transition ease-out duration-500"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-200"
>
<div class="text-left w-full">
<div class="mt-2 grid grid-cols-2 gap-x-4 gap-y-2 mb-2">
<!-- Name -->
<div class="name"
:class="errorData.name ? 'text-red-500' : ''"
>
<x-modules.label for="name" :value="__('auth.user.name')" />
<div class="relative text-gray-400 focus-within:text-gray-800">
<div class="absolute flex border border-transparent left-0 top-0 h-full w-10" >
<x-modules.svg type="user-solid" class="flex items-center justify-center rounded-l bg-gray-100 h-full w-full px-0.5"/>
</div>
<x-modules.input id="name" class="block w-full pl-12" type="text" name="name" :value="old('name')" x-model="formData.name" placeholder="Введите имя" autofocus />
</div>
<span x-text="errorData.name" class="text-red-500 text-xs"> </span>
</div>
<!-- Phone -->
<div class="phone"
:class="errorData.phone ? 'text-red-500' : ''"
>
<x-modules.label for="phone" :value="__('auth.user.phone')" />
<div class="relative text-gray-400 focus-within:text-gray-800">
<div class="absolute flex border border-transparent left-0 top-0 h-full w-10 ">
<x-modules.svg type="phone-ringing-outline" class="flex items-center justify-center rounded-l bg-gray-100 h-full w-full px-0.5"/>
</div>
<x-modules.input id="phone" class="block w-full pl-12" type="text" name="phone" :value="old('phone')" x-model="formData.phone" placeholder="Введите телефон" required autofocus />
</div>
<span x-text="errorData.phone" class="text-red-500 text-xs"> </span>
</div>
<!-- Email Address -->
<div class="email"
x-show="zamer || eskiz"
:class="errorData.email ? 'text-red-500' : ''"
>
<x-modules.label for="email" :value="__('email')" />
<div class="relative text-gray-400 focus-within:text-gray-800">
<div class="absolute flex border border-transparent left-0 top-0 h-full w-10 ">
<x-modules.svg type="envelope-outline" class="flex items-center justify-center rounded-l bg-gray-100 h-full w-full px-0.5"/>
</div>
<x-modules.input id="email" class="block w-full pl-12" type="email" name="email" :value="old('email')" x-model="formData.email" autofocus />
</div>
<span x-text="errorData.email" class="text-red-500 text-xs"> </span>
</div>
<!-- Address -->
<div class="address"
x-show="zamer || eskiz"
:class="errorData.address ? 'text-red-500' : ''"
>
<x-modules.label for="address" :value="__('auth.user.address')" />
<div class="relative text-gray-400 focus-within:text-gray-800">
<div class="absolute flex border border-transparent left-0 top-0 h-full w-10 ">
<x-modules.svg type="facade" class="flex items-center justify-center rounded-l bg-gray-100 h-full w-full px-0.5"/>
</div>
<x-modules.input id="address" class="block w-full pl-12" type="text" name="address" :value="old('address')" x-model="formData.address" autofocus />
</div>
<span x-text="errorData.address" class="text-red-500 text-xs"> </span>
</div>
<!-- Upload field -->
<div class="upload" x-show="eskiz">
<label class="flex items-center justify-evenly p-2 bg-white text-gray-700 rounded-lg shadow-lg border border-gray-300 cursor-pointer hover:bg-blue-500 hover:text-white">
<x-modules.svg type="upload" class="w-8 h-8"/>
<span>Выберите файл</span>
<input type="file" class="hidden" multiple />
</label>
</div>
</div>
<!-- Message -->
<div class="message">
<x-modules.label for="message" :value="__('auth.user.message')" />
<x-modules.textarea rows="2" id="message" class="block w-full" name="message" x-model="formData.message" placeholder="Кратко опишите ваш вопрос"/></textarea>
<span x-text="errorData.message" class="text-red-500 text-xs"> </span>
</div>
{{--
<!-- captcha -->
<div class="mt-4 captcha flex items-center space-x-2">
<div class="w-32 img">{!! captcha_img() !!}</div>
<x-modules.svg type="refresh" class="w-10 h-10 reload cursor-pointer" id="reload"/>
<x-modules.input id="captcha" class="block w-full" type="text" name="captcha" placeholder="Введите результат с картинки" x-model="formData.captcha" required />
</div>
--}}
<!-- mathcaptcha -->
<div class="mathcaptcha" :class="errorData.mathcaptcha ? 'text-red-500' : ''">
<label class="" for="mathcaptcha">Введите результат функции: <span x-text="mathcaptchaLabel" ></span></label>
<div class="flex space-x-4 text-gray-400 focus-within:text-gray-800">
<x-modules.button icon="refresh" style="black-outline" class="px-4" #click.prevent="mathcaptchaReset()" />
{!! app('mathcaptcha')->input(['class' => 'appearance-none rounded-md shadow-sm border-gray-300 placeholder-gray-400 focus:border-sky-500 focus:ring-1 focus:ring-sky-500 focus:outline-none valid:border-green-500 invalid:border-red-500 block w-full', 'id' => 'mathcaptcha', 'type' => 'text', 'name' => 'mathcaptcha', 'x-model' => 'formData.mathcaptcha']) !!}
</div>
<span x-text="errorData.mathcaptcha" class="text-red-500 text-xs"> </span>
</div>
</div>
</div>
<div class="modalfooter bg-gray-50 px-4 py-3 sm:px-6 flex justify-between ">
<x-modules.button text="Отмена" style="black-outline" class="px-4" #click.prevent="closeModal()" />
<x-modules.button x-text="buttonLabel" style="blue-solid" class="px-4" #click.prevent="submitData()" />
</div>
</div>
</form>
</div>
</div>
</div>
<!-- /Modal -->
</div>
<script>
function topbar() {
return {
mailTooltip: false,
instagramTooltip: false,
openModal: false,
callback: true,
zamer: false,
eskiz: false,
mathcaptchaLabel: '{{ app('mathcaptcha')->label() }}',
formData: {
name: '',
phone: '',
email: '',
address: '',
message: '',
mathcaptcha: '',
_token: '{{ csrf_token() }}'
},
message: '',
responseData: [],
errorStates: {
name: false,
phone: false,
email: false,
address: false,
message: false,
mathcaptcha: false
},
errorData: [],
loading: false,
sent: false,
buttonLabel: 'Отправить',
resetFields() {
this.formData.name = '',
this.formData.phone = '',
this.formData.email = '',
this.formData.address = '',
this.formData.message = '',
this.formData.mathcaptcha = ''
},
closeModal() {
this.openModal = false;
this.callback = true;
this.zamer = false;
this.eskiz = false;
},
mathcaptchaReset() {
axios.get('/reload-captcha')
.then( (response) => {
console.log(response);
this.mathcaptchaLabel = response.data.mathcaptchaLabel;
});
},
submitData() {
axios.post('/modalform', this.formData)
.then( (response) => {
this.buttonLabel = 'Отправляем...';
this.loading = true;
console.log(response);
this.resetFields();
this.sent = true;
this.message = 'Сообщение успешно отправлено!';
this.responseData = response.data;
this.mathcaptchaLabel = response.data.mathcaptchaLabel;
})
.then( () => {
this.loading = false;
this.sent = false;
this.closeModal();
this.buttonLabel = 'Отправить';
this.message = '';
})
.catch( (error) => {
console.log(error);
this.message = 'Ooops! Что-то пошло не так!'
this.errorData = error.response.data.errors;
this.isErrorCaptcha();
});
},
isErrorCaptcha() {
if (typeof (error.response.data.errors.mathcaptcha) !== 'undefined') {
this.errorStates.mathcaptcha = true;
this.mathcaptchaReset();
}
},
}
}
</script>
routes/web.php
Route::post('/modalform', 'MainController#modalform')->name('modalform');
Route::get('/reload-captcha','MainController#reloadCaptcha')->name('reloadCaptcha');
app/Http/Controllers/MainController.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Mail\Modalform;
use App\Http\Requests\ModalformRequest;
class MainController extends Controller
{
public function modalform(ModalformRequest $request) {
Mail::to( config('mail.to.address') )->send(new Modalform());
app('mathcaptcha')->reset();
return response()->json([
'status' => 'success',
'messageHeader' => 'Ваш вопрос отправлен!',
'messageContent' => 'В ближайшее время мы свяжемся с вами.',
'mathcaptchaLabel' => app('mathcaptcha')->label(),
]);
}
public function reloadCaptcha()
{
app('mathcaptcha')->reset();
return response()->json([
'mathcaptchaLabel' => app('mathcaptcha')->label(),
]);
}
}
app/Mail/Modalform.php
use Illuminate\Http\Request;
use App\Http\Requests\ModalformRequest;
use Illuminate\Mail\Mailable;
class Modalform extends Mailable
{
public function build(ModalformRequest $request)
{
$this->from( config('mail.from.address') )
->view('emails.modalform')
->withRequest($request);
}
}
App/Http/Requests/ModalformRequest.php
<?php
use Illuminate\Foundation\Http\FormRequest;
class ModalformRequest extends FormRequest
{
public function rules()
{
return [
'name' => 'bail|required|string|between:2,20',
'phone' => 'bail|required',
'email' => 'bail|email:rfc|nullable',
'address' => 'bail|string|max:100|nullable',
'message' => 'bail|string|max:500|nullable',
'mathcaptcha' => 'required|mathcaptcha',
];
}
}
Related
In my react.js frontend, I have 2 columns (Dislay event list, create event) This is how my website look like in full screen.
However, when I tried to view it with smaller screen to test the responsiveness, the background white '#F2F2F2' is not showing for the 2nd column.
How do I solve this issue?
import axios from "axios";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Button } from "../Components/customButton";
import KeyboardArrowLeftIcon from "#mui/icons-material/KeyboardArrowLeft";
import TopicList from "../Components/topicList";
import EventList from "../Components/eventList";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
const BASE_URL = process.env.REACT_APP_BASE_URL;
function CreateEvent(success, message) {
const navigate = useNavigate();
const [eventName, setEventName] = useState("");
const [eventDesc, setEventDesc] = useState("");
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const [multiplierType, setMultiplierType] = useState("");
const [multiplier, setMultiplier] = useState("");
const [topic, setTopic] = useState("");
const [eventNameCharLeft, setEventNameCharLeft] = useState(100);
const [eventDescCharLeft, setEventDescCharLeft] = useState(255);
const getDataFromTopicList = (val) => {
setTopic(val);
};
const handleEventNameChange = (event) => {
setEventName(event.target.value);
setEventNameCharLeft(100 - event.target.value.length);
};
const handleEventDescChange = (event) => {
setEventDesc(event.target.value);
setEventDescCharLeft(255 - event.target.value.length);
};
const handleSubmit = (event) => {
event.preventDefault();
axios({
method: "POST",
url: BASE_URL + "events/submitEvent",
data: {
eventName: eventName,
eventDesc: eventDesc,
eventStart: startDate,
eventEnd: endDate,
topicId: topic,
multiplierType: multiplierType,
multiplier: multiplier,
status: "Upcoming",
},
headers: { "Content-Type": "application/json" },
})
.then((response) => {
if (response.status === 200) {
toast.success("Successfully Created", {
position: toast.POSITION.TOP_CENTER,
});
} else {
toast.error(response.data.message, {
position: toast.POSITION.TOP_CENTER,
});
}
})
.catch((err) => {
if (err.response) {
toast.error(err.response.data.message, {
position: toast.POSITION.TOP_CENTER,
});
} else {
toast.error("Failed to Create", {
position: toast.POSITION.TOP_CENTER,
});
}
});
};
return (
<div className="min-h-screen">
<Button
variant="primary"
className="absolute top-4 left-6 px-0 py-2 font-bold btn btn-primary text-main-blue"
onClick={() => {navigate(`/Admin`);}}
isDisabled={false}
buttonText="Back"
icon={<KeyboardArrowLeftIcon color="main-green" />}
/>
<div className=" grid grid-cols-2 p-20 space-x-8 sm:grid-cols-1 md:grid-cols-1 h-screen lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2">
<div className="px-4 pt-4 pb-8 mb-4 bg-slate-50 drop-shadow-xl rounded-2xl">
{/* Ongoing Events */}
<h1 className="py-3 my-2 font-semibold border-b-2 text-main-blue border-main-blue">Ongoing Events</h1>
<div className="grid grid-cols-3 pt-2 gap-x-10">
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Event Name</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Start Date</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">End Date</h1>
</div>
</div>
<EventList url="events/getOngoing" />
{/* Upcoming Events */}
<h1 className="py-3 my-2 font-semibold border-b-2 text-main-blue border-main-blue">Upcoming Events</h1>
<div className="grid grid-cols-3 pt-2 gap-x-10">
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Event Name</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Start Date</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">End Date</h1>
</div>
</div>
<EventList url="events/getUpcoming" />
{/* Past Events */}
<h1 className="py-3 my-2 font-semibold text-gray-400 border-b-2 border-gray-400">Past Events</h1>
<div className="grid grid-cols-3 pt-2 gap-x-10">
<div className="">
<h1 className="pb-3 text-sm font-semibold text-gray-400">Event Name</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-gray-400">Start Date</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-gray-400">End Date</h1>
</div>
</div>
<EventList url="events/getPast" />
</div>
<form
className="px-8 pt-6 pb-8 mb-4 rounded sm:grid-cols-1 md:grid-cols-1 bg-white" onSubmit={handleSubmit}>
<h1 className="text-2xl font-bold pt-15 text-main-blue">Create an Event</h1>
<div>
<textarea
className="block w-full px-5 py-2 mt-2 overflow-y-auto text-sm break-words border border-gray-300 rounded-md bg-slate-50 text-main-blue drop-shadow-lg"
name="eventName" placeholder="Event Name" required onChange={handleEventNameChange} value={eventName}maxLength={100}>
</textarea>
<div className="mt-2 text-sm text-gray-500">
{eventNameCharLeft}/100 characters left
</div>
<textarea
className="block w-full px-5 py-2 mt-2 overflow-y-auto text-sm break-words border border-gray-300 rounded-md bg-slate-50 text-main-blue drop-shadow-lg"
name="eventDesc" placeholder="Event Description" required onChange={handleEventDescChange} value={eventDesc} maxLength={255}>
</textarea>
<div className="mt-2 text-sm text-gray-500">
{eventDescCharLeft}/255 characters left
</div>
<div className="grid grid-cols-2 gap-x-2 mt-4">
<div className="relative">
<label className="absolute text-sm text-gray-500">Start Date</label>
<input
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md my-5 block w-full p-2.5"
type="datetime-local" name="startDate" placeholder="Start Date" required onChange={(event) => setStartDate(event.target.value)} value={startDate}/>
</div>
<div className="relative">
<label className="absolute text-sm text-gray-500">End Date</label>
<input
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md my-5 block w-full p-2.5"
type="datetime-local" name="endDate" placeholder="End Date" required onChange={(event) => setEndDate(event.target.value)} value={endDate}/>
</div>
</div>
<div className="grid grid-cols-2 gap-x-2">
<TopicList getDataFromTopicList={getDataFromTopicList} />
<select
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md block w-auto p-2.5"
name="multiplierType" required onChange={(event) => setMultiplierType(event.target.value)} value={multiplierType}>
<option value="" disabled selected>Select Multiplier</option>
<option value="+">Add</option>
<option value="*">Multiply</option>
</select>
</div>
<input
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md my-5 block w-full p-2.5"
type="number" name="multiplier" placeholder="Multiplier Value (Eg 1-100)" min="1" max="100" required onChange={(event) => setMultiplier(event.target.value)} value={multiplier}/>
</div>
<div className="relative p-4">
<Button
variant="primary"
className="absolute bottom-0 right-0 px-4 py-2 -my-5 font-bold border rounded btn btn-primary bg-slate-50 text-main-blue border-main-blue hover:border-transparent hover:bg-main-blue hover:text-slate-50"
isDisabled={false}
buttonText="Submit"
type="submit"
/>
<ToastContainer autoClose={4000} />
</div>
</form>
</div>
</div>
);
}
export default CreateEvent;
This is the output for small screen in tailwind playground.
This seems to work just fine for me !
Code Link: tailwind_playground
Output in large screen:
Output in small screen:
Your problem is "h-screen" in the class name on the element you have selected in your screenshot. This prevents it from extending to the height of the elements inside it. You can change this to "min-h-screen" as well however, I would recommend just removing it entirely.
I have put in a mouseenter and mouseleave on the li tag that i want when a person hovers over it, it will display the price on product.price. However, when i hover over it, it will display the price for all 6 rendered data instead of just the 1 its hovered on. I only want it to display pricing on the specific item its hovered on and not all. The data is being loaded from firebase. Please see below template code and image here for reference.
<div class="relative w-full pb-6 -mb-6 overflow-x-auto scrollbar-hide">
<ul role="list" class="mx-4 inline-flex space-x-0 gap-2 sm:mx-6 lg:mx-0 lg:space-x-0 lg:grid lg:grid-cols-6 lg:gap-x-4">
<li v-if="products.length" v-for="product in products" :key="product.id" #mouseenter="hover = true" #mouseleave="hover = false" class="w-44 inline-flex border hover:border-black rounded-lg p-4 lg:w-auto">
<div class="group relative">
<div class="w-[70%] lg:w-[55%] bg-gray-white overflow-hidden">
<img :src="product.imageSrc" :alt="product.imageAlt" class="w-full h-20 overflow-hidden object-center object-contain" />
</div>
<div class="mt-2">
<h3 class="mt-1 font-rubikreg h-11 overflow-hidden text-xs lg:text-base uppercase text-gray-900">
<a :href="product.href">
<span class="absolute inset-0" />
{{ product.name }}
</a>
</h3>
<p class="mt-3 lg:mt-6 font-rubiklight uppercase text-xs lg:text-sm text-gray-900">
Cheapest At
</p>
<p class="mt-1 font-rubikreg underline-offset-2 underline uppercase text-xs lg:text-sm text-gray-900">
{{ product.cheapestat }}
</p>
<p v-if="hover" class="mt-5 text-2xl uppercase font-rubik text-gray-900">
<span class="text-xs">From</span>
A${{ product.price }}
</p>
</div>
</div>
</li>
</ul>
</div>
script code on firebase data
setup() {
onMounted(() => {
onSnapshot(collection(db, "malesneakers") , (querySnapshot) => {
const maleProducts = [];
querySnapshot.forEach((doc) => {
const mlproducts = {
id: doc.id,
imageSrc: doc.data().imageSrc,
name: doc.data().name,
price: doc.data().price,
cheapestat: doc.data().cheapestat,
svgSrc: doc.data().svgSrc,
href: doc.data().href,
}
maleProducts.push(mlproducts)
});
products.value = maleProducts
});
});
Try with product.id instead of boolean for hover variable:
const { ref } = Vue
const app = Vue.createApp({
setup() {
const products = ref([{id: 1, name: 'aaa', href: '#', cheapestat: 5, price: 7}, {id: 2, name: 'bbb', href: '#', cheapestat: 5, price: 5}])
const hover = ref(null)
return {
products, hover
};
},
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" integrity="sha512-wnea99uKIC3TJF7v4eKk4Y+lMz2Mklv18+r4na2Gn1abDRPPOeef95xTzdwGD9e6zXJBteMIhZ1+68QC5byJZw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div id="demo">
<div class="relative w-full pb-6 -mb-6 overflow-x-auto scrollbar-hide">
<ul v-if="products.length" role="list" class="mx-4 inline-flex space-x-0 gap-2 sm:mx-6 lg:mx-0 lg:space-x-0 lg:grid lg:grid-cols-6 lg:gap-x-4">
<!-- 👇 here you set hover to product.id -->
<li v-for="product in products" :key="product.id"
#mouseenter="hover = product.id" #mouseleave="hover = null" class="w-44 inline-flex border hover:border-black rounded-lg p-4 lg:w-auto">
<div class="group relative">
<div class="w-[70%] lg:w-[55%] bg-gray-white overflow-hidden">
<img :src="product.imageSrc" :alt="product.imageAlt" class="w-full h-20 overflow-hidden object-center object-contain" />
</div>
<div class="mt-2">
<h3 class="mt-1 font-rubikreg h-11 overflow-hidden text-xs lg:text-base uppercase text-gray-900">
<a :href="product.href">
<span class="absolute inset-0" />
{{ product.name }}
</a>
</h3>
<p class="mt-3 lg:mt-6 font-rubiklight uppercase text-xs lg:text-sm text-gray-900">
Cheapest At
</p>
<p class="mt-1 font-rubikreg underline-offset-2 underline uppercase text-xs lg:text-sm text-gray-900">
{{ product.cheapestat }}
</p>
<!-- 👇 here you check hover for product.id -->
<p v-if="hover === product.id" class="mt-5 text-2xl uppercase font-rubik text-gray-900">
<span class="text-xs">From</span>
A${{ product.price }}
</p>
</div>
</div>
</li>
</ul>
</div>
</div>
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class ProductController extends Controller
{
public function store(Request $request) {
$this->validate($request,[
'productName' =>'required|max:255',
'quantity' =>'required',
'weight' =>'required',
'boxes' =>'required',
'MRP' =>'required',
'costprice' =>'required',
'image' =>'required|image|mimes:png,jpeg,jpg,gif,svg|max:2048',
'productDescription' =>'required',
]);
$imageName = time().'.'.$request->image->extension();
Product::create([
'productName' => $request->productName,
'quantity' => $request->quantity,
'weight' => $request->weight,
'boxes' => $request->boxes,
'MRP' => $request->MRP,
'costprice' =>$request->costprice,
'productDescription' =>$request->productDescription,
'image' =>$request->image->move(public_path('images'),$imageName),
'seller_id' => $request->user('seller')->id,
'category_id' => $request->category
]);
return back()->with('success','Product stocked Successfully...');
}
}
can't get the problem solved with this code here is my blade file whenever i am submitting form it is not inserting data in database which is a problem and i have checked everthing including model , migration etc. but not getting any error but still data is not getting submit
<div class='w-75 justify-end'>
<form action="{{ route('products') }}" class='w-100 bg-white p-6 rounded-lg mt-1'
method='post'>
#csrf
#if(session()->has('success'))
<div class='alert alert-success'>
<ul>
<li>{{ session()->get('success')}}</li>
</ul>
</div>
#endif
<fieldset class='w-100 inline-flex bg-grey scheduler-border'>
<legend class='text-secondary font-bold border-bottom w-50 text-left ml-4 px-10 py-1'>Add
Product </legend>
<div class='flex w-100'>
<div class='control-group flex flex-col ml-3 mb-4 w-25 p-3'>
<label for="image" class='sr-only'>Image</label>
<input type="file" name='image' id='image'
class='form-control bg-gray-100 border-2 w-75 h-25 p-2 rounded-lg mb-4'>
<label for="productName" class='sr-only'>Product Name</label>
<input type="text" name='productName' id='productName' placeholder= 'product Name'
class='bg-gray-100 border-2 w-75 p-2 h-10 rounded-lg mb-8 #error('productName') ?
border border-danger : '' #enderror' value='{{ old('productName') }}'>
<label for="category" class='sr-only'>Category</label>
<select type="dropdown" name='category' id='category'
class='bg-gray-100 text-secondary border-2 w-75 h-10 rounded-lg mb-2'>
<option selected>select category</option>
#foreach($categoryname as $data)
<option value="{{ $data->id }}">{{ $data->categoryName }}</option>
#endforeach
</select>
<div class='form-check w-100 ml-0 m-2 p-2'>
<i>Status:</i>
<input class='form-check-input mt-2 ml-3' type="checkbox"
name='flexCheckChecked'
id='flexCheckChecked' class='bg-gray-100 border-2 w-25 p-2 rounded-lg mb-4' checked>
<label class='form-check-label ml-8' for="flexCheckChecked">active</label>
</div>
</div>
<div class='control-group mb-4 p-3 w-50'>
<label for="product description" class='sr-only'>Product description</label>
<textarea name='productDescription' id='productDescription' placeholder='Add
product description'
class='bg-gray-100 border-2 w-75 h-25 p-2 rounded-lg mb-2
#error('productDescription') ? border border-danger : '' #enderror' value='{{
old('productDescription') }}' cols="40" rows="10"></textarea>
<div class='flex mt-2'>
<label for="Unit price" class='sr-only'>Unit price</label>
<input type="number" name='costprice' min=1 id='costprice' placeholder='Unit
price' class='bg-gray-100 border-2 text-sm w-25 p-2 rounded-lg mb-4
#error('costprice') ? border border-danger : '' #enderror' value='{{
old('costprice') }}'>
<small class='text-secondary p-2 font-italic'>(Rs.)</small>
<label for="weight" class='sr-only'>weight</label>
<input type="number" name='weight' min=1 id='weight' placeholder= 'Weight'
class='bg-gray-100 border-2 w-25 text-sm p-2 rounded-lg mb-4 ml-4
#error('weight') ? border border-danger : '' #enderror' value='{{ old('weight')
}}'>
<small class='text-secondary p-2 font-italic'>(g)</small>
</div>
<div class='flex'>
<label for="quantity" class='sr-only'>Quantity</label>
<input type="number" name='quantity' min=1 id='quantity' placeholder= 'Quantity'
class='bg-gray-100 border-2 text-sm w-25 p-2 rounded-lg mb-4
#error('quantity') ? border border-danger : '' #enderror' value='{{
old('quantity') }}'>
<small class='text-secondary p-2 font-italic'>(per box)</small>
<label for="boxes" class='sr-only'>Boxes</label>
<input type="number" name='boxes' min=1 id='boxes' placeholder= 'Boxes'
class='bg-gray-100 border-2 w-25 p-2 rounded-lg mb-4 #error('boxes') ? border
border-danger : '' #enderror' value='{{ old('boxes') }}'>
<small class='text-secondary p-2 text-sm font-italic'>(cartoon)</small>
</div>
<div class='mb-4 flex justify-start'>
<input type="number" name='MRP' min=1 id='MRP' placeholder= 'MRP'
class='bg-gray-100 border-2 w-25 text-sm p-2 rounded-lg mb-4 #error('MRP') ?
border border-danger : '' #enderror' value='{{ old('MRP') }}'>
<small class='text-secondary p-2 font-italic mr-4'>(Rs.)</small>
<button type="submit" class='w-25 h-10 bg-blue-500 text-white text-center font-
medium py-1 rounded-lg'><b>+</b> Add Product</button>
</div>
</div>
</div>
</fieldset>
</form>
<hr class='bg-grey-500'>
</div>
I want my code to insert data in my database but it is getting back and not providing error
or success if i check my database there is no data please resolve issue
You can use it like this:
$request->validate($rules);
or
$request->validate([
'productName' => 'required|max:255'
]);
Then it returns the errors.
$test = $productName->validate([
'productName' => 'required|max:255'
]);
and you need to check if there are no errors and then you can do what ever you want.
In your case you need to do it like this:
$validator = Validator::make($request->all(), [
'productName' => 'required|max:255'
]);
if ($validator->fails()) {
return back()->with('failed','There is error');
} else {
return back()->with('success','Product stocked Successfully...');
}
I've working with app made with TALL. On local work fine, and on production one page with 3 forms, get error "405 Method Not Allowed"
Error trace show a problem on POST method instead GET method.
The form is a mix of three forms.
1- The one with the profile
2. The one with the password
3. The one with the token
All three forms are components of livewire.
Each one has their buton, to save.
Thus, the error occurs in any of the three save buttons, in production.
wep.php
Route::group(['prefix' => 'dashboard', 'as' => 'admin.', 'middleware' => ['auth']], function () {
...
Route::get('/profile', Profile::class)->name('profile');
...
}
Profile.php
<?php
namespace App\Http\Livewire\Auth;
use App\Models\User;
use Livewire\Component;
class Profile extends Component
{
public User $user;
public function mount() { $this->user = auth()->user(); }
public function render()
{
return view('livewire.auth.profile');
}
}
UpdatePassword.php
<?php
namespace App\Http\Livewire\Auth\Profile;
use Livewire\Component;
use App\Models\User;
class UpdatePassword extends Component
{
//public User $user;
public $password;
public $password_confirmation;
public function render()
{
return view('livewire.auth.profile.update-password');
}
protected $rules = [
'password' => [
'required',
'confirmed',
'min:10',
'regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[!$#%]).*$/',
],
];
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function save()
{
$this->validate();
auth()->user()->update([
'password' => bcrypt($this->password)
]);
$this->emitSelf('notify-saved');
$this->resetForm();
}
protected function resetForm()
{
$this->password = '';
$this->password_confirmation = '';
}
}
UpdateProfile.php
<?php
namespace App\Http\Livewire\Auth\Profile;
use App\Models\User;
use Livewire\Component;
use Livewire\WithFileUploads;
class UpdateProfile extends Component
{
use WithFileUploads;
public User $user;
public $upload;
public function render()
{
return view('livewire.auth.profile.update-profile');
}
protected function rules(): array
{
return [
'user.name' => [
'string',
'required',
'min:5',
],
'user.email' => [
'email:rfc',
'required',
'regex:/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*#([a-z0-9\-]+\.)+[a-z]{2,6}$/ix',
'unique:users,email,' . $this->user->id,
],
'upload' => [
'nullable',
'image',
'mimes:jpg,bmp,png',
'max:200'
],
];
}
public function mount() { $this->user = auth()->user(); }
public function save()
{
$this->validate();
$this->user->save();
$this->upload && $this->user->update([
'avatar' => $this->upload->store('/', 'avatars'),
]);
$this->emitSelf('notify-saved');
}
}
UpdateToken.php
<?php
namespace App\Http\Livewire\Auth\Profile;
use App\Helpers\ApiHelpers;
use Livewire\Component;
class UpdateToken extends Component
{
public string $token;
public function mount()
{
$this->resetState();
}
public function updateToken()
{
$user = auth()->user();
ApiHelpers::deleteTokenUserType($user->id, 'auth_token');
$this->token = auth()->user()->createToken('auth_token')->plainTextToken;
}
public function render()
{
return view('livewire.auth.profile.update-token');
}
protected function resetState()
{
$this->token = '';
}
}
profile.blade.php
<div>
#livewire('auth.profile.update-profile')
<!-- Contraseña -->
<div class="hidden sm:block" aria-hidden="true">
<div class="py-5">
<div class="border-t border-gray-200"></div>
</div>
</div>
#livewire('auth.profile.update-password')
<!-- Token -->
<div class="hidden sm:block" aria-hidden="true">
<div class="py-5">
<div class="border-t border-gray-200"></div>
</div>
</div>
#livewire('auth.profile.update-token')
</div>
update-profile.blade.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6 border-gray-300">
<div class="md:col-span-1">
<h3 class="text-lg font-medium leading-6 text-gray-900">Perfil</h3>
<p class="mt-1 text-sm text-gray-500">
Esta información es privada y sólo tiene efectos administrativos.
</p>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form wire:submit.prevent="save">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<!-- Nombre -->
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="name" class="block text-sm font-medium text-gray-700">
Nombre
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="user.name" type="text" name="username" id="username" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Nombre y apellidos">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
#error('user.name')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
#enderror
</div>
</div>
</div>
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="email" class="block text-sm font-medium text-gray-700">
Email
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="user.email" type="text" name="email" id="email" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Correo electrónico">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
#error('user.email')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
#enderror
</div>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">
Foto
</label>
<div class="mt-1 flex items-center space-x-5">
<span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">
#if ($upload)
<img src="{{ $upload->temporaryUrl() }}" alt="Profile Photo">
#else
<img src="{{ auth()->user()->avatarUrl() }}" alt="Profile Photo">
#endif
</span>
<input type="file" wire:model="upload" id="photo">
<div class="mt-1 relative rounded-md shadow-sm">
#error('user.avatar')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
#enderror
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Save
</button>
<span x-data="{ open: false }"
x-init="#this.on('notify-saved',
() => {
if (open === false) setTimeout(() => { open = false }, 3500);
open = true;
})"
x-show.transition.out.duration.1000ms="open"
style="display: none;"
class="text-gray-500">¡Guardado!</span>
</div>
</div>
</form>
</div>
</div>
</div>
update-password.blade.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6 border-gray-300">
<div class="md:col-span-1">
<h3 class="text-lg font-medium leading-6 text-gray-900">Contraseña</h3>
<p class="mt-1 text-sm text-gray-500">
Puede cambiar su contraseña en este formulario
</p>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form wire:submit.prevent="save">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="password" class="block text-sm font-medium text-gray-700">
Contraseña
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="password" type="password" name="password" id="password" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Nueva contraseña">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
#error('password')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
#enderror
</div>
</div>
</div>
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="password_confirmation" class="block text-sm font-medium text-gray-700">
Confirma la contraseña
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="password_confirmation" type="password" name="password_confirmation" id="password_confirmation" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
#error('password_confirmation')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
#enderror
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Cambiar
</button>
<span x-data="{ open: false }"
x-init="#this.on('notify-saved',
() => {
if (open === false) setTimeout(() => { open = false }, 3500);
open = true;
})"
x-show.transition.out.duration.1000ms="open"
style="display: none;"
class="text-gray-500">¡Contraseña cambiada!
</span>
</div>
</div>
</form>
</div>
</div>
</div>
update-token.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6 border-gray-300">
<div class="md:col-span-1">
<h3 class="text-lg font-medium leading-6 text-gray-900">Token API</h3>
<p class="mt-1 text-sm text-gray-500">
El token solo se muestra una vez generado, por seguridad.
<br />Copielo y guardelo en un lugar seguro.
<br />El anterior se elimina del sistema, dejan de ser operativo.
</p>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form wire:submit.prevent="updateToken">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="token" class="block text-sm font-medium text-gray-700">
Token
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model="token" type="text" name="token" id="token" disabled class="disabled:opacity-50 focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Haz click en el botón para regenerar el token">
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Regenerar
</button>
</div>
</div>
</form>
</div>
</div>
</div>
An unforgivable mistake.
As a system administrator, I have forgotten, that you have to review the logs. And among others the mod_security log.
--9ac02665-F--
HTTP/1.1 405 Method Not Allowed
allow: POST
Cache-Control: no-cache, private
date: Fri, 12 Nov 2021 15:18:31 GMT
Connection: close
Content-Type: text/html; charset=UTF-8
Server: Apache
--9ac02665-H--
Message: Warning. Matched phrase ".profile" at REQUEST_FILENAME. [file "/etc/apache2/conf.d/modsec_vendor_configs/OWASP3/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "124"] [id "930130"] [msg "Restricted File Access Attempt"] [data "Matched Data: .profile found within REQUEST_FILENAME: /livewire/message/auth.profile.update-profile"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.2"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153/126"] [tag "PCI/6.5.4"]
I have a simple login form on a sliding modal. On desktop and in responsive mode with dev tools it looks as it should. However on mobile Chrome and Safari -- on an iphone, there's a weird gray rounded box or shadow.
I'm using tialwind css. And the component was built with headless ui.
I've tried adding -webkit-appearance: none; to the form, but the box still persits.
Here's how it looks on desktop:
desktop view
and here is how it looks on my iphone:
mobile view
here is the component code:
return (
<Transition.Root show={showModal.open} as={Fragment}>
<Dialog
as="div"
className="fixed inset-0 overflow-hidden"
onClose={() => setShowModal({ open: false })}
>
<div className="absolute inset-0 overflow-hidden">
<Transition.Child
as={Fragment}
enter="ease-in-out duration-500"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in-out duration-500"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="absolute inset-0 bg-black bg-opacity-80 transition-opacity" />
</Transition.Child>
<div className="fixed inset-y-0 right-0 pl-10 max-w-full flex">
<Transition.Child
as={Fragment}
enter="transform transition ease-in-out duration-500 sm:duration-700"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transform transition ease-in-out duration-500 sm:duration-700"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<div className="w-screen max-w-md">
<div className="h-full flex flex-col py-6 bg-white shadow-xl overflow-y-scroll">
<div className="px-4 sm:px-6">
<div className="flex items-start justify-between">
<Dialog.Title className="text-2xl font-light text-vhGreen">
Welcome!
</Dialog.Title>
<div className="ml-3 h-7 flex items-center">
<button
type="button"
className="bg-white rounded-md text-vhGreen hover:text-gray-500 focus:outline-none"
onClick={() => setShowModal({ open: false })}
>
<span className="sr-only">Close panel</span>
<XCircleIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
</div>
</div>
<div className="mt-6 relative flex-1 px-4 sm:px-6">
{/* Replace with your content */}
<div className="absolute inset-0 px-4 sm:px-6">
<div className="relative p-6 flex-auto bg-white">
<h4 className="text-vhGreen font-light">
Login or sign up to gain access to the gallery and to
receive periodic updates from Thea
</h4>
<form
type="submit"
onSubmit={(e) => handleSubmit(e)}
className="bg-white"
>
{isNewUser && (
<>
<div className="my-4 text-sm">
<label className="block text-vhGreen">
First Name
</label>
<input
value={authForm.firstName || ""}
onChange={(e) => handleChange(e)}
type="text"
name="firstName"
placeholder="First Name"
className="w-full px-4 py-3 rounded-md text-vhGreen font-light"
/>
</div>
<div className="my-4 text-sm">
<label className="block text-vhGreen">
Last Name
</label>
<input
value={authForm.lastName || ""}
onChange={(e) => handleChange(e)}
type="text"
name="lastName"
placeholder="Last Name"
className="w-full px-4 py-3 rounded-md"
/>
</div>
</>
)}
<div className="my-4 text-sm">
<label className="block text-vhGreen">Email</label>
<input
value={authForm.email || ""}
onChange={(e) => handleChange(e)}
type="text"
name="email"
placeholder="Email"
className="w-full px-4 py-3 rounded-md"
/>
</div>
<div className="my-4 text-sm">
<label className="block text-vhGreen">
Password
</label>
<input
value={authForm.password || ""}
onChange={(e) => handleChange(e)}
type="password"
name="password"
placeholder="Password"
className="w-full px-4 py-3 rounded-md"
onKeyDown={(e) => onKeyDown(e)}
/>
<div className="flex justify-end text-vhGreen text-sm font-light">
<button
type="button"
onClick={() => handleNewSwitch()}
>
{!isNewUser
? "Need an account? Sign Up!"
: "Already have an account? Login!"}
</button>
</div>
</div>
</form>
</div>
{/*footer*/}
<div className="flex items-center justify-center p-6 border-t border-solid border-blueGray-200 rounded-b">
<button
className="text-vhGreen background-transparent font-light uppercase px-6 py-2 text-xl outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
onClick={(e) => handleSubmit(e)}
>
{isNewUser ? "Sign Up" : "Login"}
</button>
</div>
</div>
{/* /End replace */}
</div>
</div>
</div>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
faced same thing.
The problem is in:
type="button"
Try to remove that, works for me