feat: working form
This commit is contained in:
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "lf",
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"insertPragma": false,
|
||||
"singleAttributePerLine": false,
|
||||
"bracketSameLine": false,
|
||||
"jsxBracketSameLine": false,
|
||||
"jsxSingleQuote": true,
|
||||
"printWidth": 120,
|
||||
"proseWrap": "preserve",
|
||||
"quoteProps": "as-needed",
|
||||
"requirePragma": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": false,
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"vueIndentScriptAndStyle": false,
|
||||
"experimentalTernaries": false,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.ts",
|
||||
"options": {
|
||||
"parser": "typescript"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.vue",
|
||||
"options": {
|
||||
"parser": "vue"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { ErrorMessage, Field } from 'vee-validate'
|
||||
|
||||
defineProps<{
|
||||
type: 'text' | 'email' | 'password'
|
||||
name: string
|
||||
label: string
|
||||
required?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-1">
|
||||
<Field :type="type" :name="name" class="input" :placeholder="label" :required="required" />
|
||||
<ErrorMessage :name="name" as="span" class="text-error" />
|
||||
</div>
|
||||
</template>
|
||||
+30
-45
@@ -1,56 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import { toTypedSchema } from "@vee-validate/zod";
|
||||
import { useForm } from "vee-validate";
|
||||
import z from "zod";
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { ref } from 'vue'
|
||||
import FormField from './FormField.vue'
|
||||
import { loginSchema, type LoginForm as LoginFormData } from '../schemas/login'
|
||||
|
||||
defineProps<{
|
||||
email: string;
|
||||
}>();
|
||||
const props = defineProps<{
|
||||
email: string
|
||||
error?: string
|
||||
}>()
|
||||
|
||||
interface Form {
|
||||
email: string;
|
||||
password: string;
|
||||
const form = ref<HTMLFormElement>()
|
||||
|
||||
const { handleSubmit } = useForm<LoginFormData>({
|
||||
initialValues: {
|
||||
email: props.email,
|
||||
password: '',
|
||||
},
|
||||
validationSchema: toTypedSchema(loginSchema),
|
||||
})
|
||||
|
||||
const onSubmit = handleSubmit((data) => {
|
||||
const emailInput = form.value?.elements.namedItem('email')
|
||||
|
||||
if (emailInput instanceof HTMLInputElement) {
|
||||
emailInput.value = data.email
|
||||
}
|
||||
|
||||
const { handleSubmit } = useForm<Form>({
|
||||
initialValues: {
|
||||
email: "",
|
||||
password: "",
|
||||
},
|
||||
validationSchema: toTypedSchema(
|
||||
z.object({
|
||||
email: z.email(),
|
||||
password: z.string().min(8),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
console.log(data);
|
||||
});
|
||||
form.value?.submit()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form
|
||||
method="post"
|
||||
class="container mx-auto p-4 flex flex-col gap-4"
|
||||
@submit.prevent="onSubmit"
|
||||
>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
class="input"
|
||||
placeholder="E-Mail"
|
||||
required
|
||||
:value="email"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
class="input"
|
||||
placeholder="Password"
|
||||
required
|
||||
/>
|
||||
<form ref="form" method="post" class="container mx-auto p-4 flex flex-col gap-4" @submit="onSubmit">
|
||||
<div v-if="error" class="alert alert-error">{{ error }}</div>
|
||||
<FormField type="email" name="email" label="E-Mail" required />
|
||||
<FormField type="password" name="password" label="Password" required />
|
||||
<button type="submit" class="btn btn-primary self-start">Sign in</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
+20
-11
@@ -1,23 +1,32 @@
|
||||
---
|
||||
import Layout from "../layouts/layout.astro";
|
||||
import LoginForm from "../islands/LoginForm.vue";
|
||||
import LoginForm from '../islands/LoginForm.vue'
|
||||
import Layout from '../layouts/layout.astro'
|
||||
import { loginSchema } from '../schemas/login'
|
||||
|
||||
let email = "";
|
||||
let error = "";
|
||||
let email = ''
|
||||
let error = ''
|
||||
|
||||
if (Astro.request.method === "POST") {
|
||||
const formData = await Astro.request.formData();
|
||||
if (Astro.request.method === 'POST') {
|
||||
const formData = await Astro.request.formData()
|
||||
const input = {
|
||||
email: formData.get('email'),
|
||||
password: formData.get('password'),
|
||||
}
|
||||
const result = loginSchema.safeParse(input)
|
||||
|
||||
email = formData.get("email")?.toString() ?? "";
|
||||
email = typeof input.email === 'string' ? input.email : ''
|
||||
|
||||
if (!email) {
|
||||
error = "E-Mail shouldn't be empty.";
|
||||
if (!result.success) {
|
||||
error = result.error.issues[0]?.message ?? 'Invalid form data.'
|
||||
} else {
|
||||
email = result.data.email
|
||||
console.log('POST DATA', result.data)
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<h1 class="text-2xl font-bold">Sign in</h1>
|
||||
<h1 class='text-2xl font-bold'>Sign in</h1>
|
||||
|
||||
<LoginForm client:load email={email} />
|
||||
<LoginForm client:load email={email} error={error} />
|
||||
</Layout>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import z from 'zod'
|
||||
|
||||
export const loginSchema = z.object({
|
||||
email: z.string().trim().pipe(z.email()),
|
||||
password: z.string().min(8),
|
||||
})
|
||||
|
||||
export type LoginForm = z.infer<typeof loginSchema>
|
||||
Reference in New Issue
Block a user