Skip to content

Commit

Permalink
Merge pull request #1 from qirolab/useSanctumForm
Browse files Browse the repository at this point in the history
Use sanctum form
  • Loading branch information
hkp22 authored Oct 22, 2024
2 parents 3706e4c + 3fd73e6 commit 8bbadb1
Show file tree
Hide file tree
Showing 80 changed files with 3,258 additions and 45 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ node_modules
.env
dist
public/codemirror
test/fixtures/laravel-api
15 changes: 14 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
{
"eslint.experimental.useFlatConfig": true
"eslint.useFlatConfig": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
}
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,34 @@ Contributions to the `nuxt-sanctum-authentication` module are welcome! Whether i
5. Push your changes to your forked repository.
6. Submit a pull request.


## Support

If you found this demo helpful and want to support my work, check out some of my other products:

<div style="display:flex;">
<a href="https://qirolab.com/ctrl-alt-cheat" title="Ctrl+Alt+Cheat - The Ultimate Cheat Sheets at Your Fingertips">
<img width="200" src="https://i.imgur.com/6igLwXU.png" alt="Ctrl+Alt+Cheat" />
</a>
&nbsp;&nbsp;&nbsp;
<a href="https://qirolab.com/spec-coder" title="Spec Coder: AI-Powered VS Code Extension">
<img width="200" src="https://i.imgur.com/zHSNlJu.png" alt="Spec Coder" />
</a>
&nbsp;&nbsp;&nbsp;
<a href="https://qirolab.gumroad.com/l/javascript-from-es2015-to-es2023" title="JavaScript: A Comprehensive Guide from ES2015 to ES2023 - eBook">
<img width="200" src="https://i.imgur.com/vXnJAul.png" alt="JavaScript Guide" />
</a>
</div>


---

#### Get $200 free credit for DigitalOcean! (Use this link to sign up)

[![DigitalOcean Referral
Badge](https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%201.svg)](https://www.digitalocean.com/?refcode=e740238537d0&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge)


---

## License
Expand Down
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export default createConfigForNuxt({
},
},
],
'@stylistic/arrow-parens': 'off',
'prettier/prettier': 'error',
},
settings: {
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"dev:build": "nuxi build playground",
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
"release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
"lint": "eslint .",
"lint": "eslint . --ignore-pattern 'test/fixtures/laravel-api/*'",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"test": "vitest run",
Expand All @@ -52,7 +52,9 @@
},
"dependencies": {
"@nuxt/kit": "^3.12.4",
"defu": "^6.1.4"
"defu": "^6.1.4",
"lodash-es": "^4.17.21",
"object-to-formdata": "^4.5.1"
},
"devDependencies": {
"@nuxt/devtools": "^1.3.9",
Expand All @@ -61,6 +63,7 @@
"@nuxt/schema": "^3.12.4",
"@nuxt/test-utils": "^3.14.1",
"@types/eslint-config-prettier": "^6.11.3",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.14.11",
"changelogen": "^0.5.5",
"eslint": "^9.9.0",
Expand Down
4 changes: 2 additions & 2 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ export default defineNuxtConfig({
devtools: { enabled: true },

devServer: {
host: 'laravel-api.test',
host: 'localhost',
},

laravelSanctum: {
apiUrl: 'http://laravel-api.test',
apiUrl: 'http://localhost:8000',
authMode: 'cookie',
userStateKey: 'sanctum.authenticated.user',
token: {
Expand Down
115 changes: 83 additions & 32 deletions playground/pages/profile.vue
Original file line number Diff line number Diff line change
@@ -1,39 +1,36 @@
<script lang="ts" setup>
import { FetchError } from 'ofetch';
definePageMeta({
middleware: ['$auth'],
});
const { user, refreshUser } = useSanctum<{ name: string; email: string }>();
const { user, refreshUser } = useSanctum<{
name: string;
email: string;
avatar: string;
}>();
const form = ref({
name: '',
email: '',
const form = useSanctumForm<{
name: string;
email: string;
avatar: File | null;
}>('post', '/api/profile', {
name: user.value!.name,
email: user.value!.email,
avatar: null,
});
const errors = ref<{ [key: string]: string[] }>({});
interface User {
name: string;
email: string;
}
async function submit() {
try {
await useSanctumFetch('/api/profile', {
method: 'post',
body: form.value,
});
await refreshUser();
} catch (error) {
if (error instanceof FetchError && error.response?.status === 422) {
errors.value = error.response?._data.errors;
console.log(error.response?._data.errors);
}
}
await form.submit<User>();
await refreshUser();
}
onMounted(() => {
form.value.name = user.value!.name;
form.value.email = user.value!.email;
});
function resetForm() {
form.reset();
}
</script>

<!-- eslint-disable vue/singleline-html-element-content-newline -->
Expand All @@ -42,19 +39,66 @@ onMounted(() => {
<template>
<form @submit.prevent="submit">
<div class="profile-form">
<h1 class="heading">Profile</h1>
<pre>{{ user }}</pre>
<h1 v-if="user" class="heading">Profile: {{ user.name }}</h1>
<div
v-if="user && user.avatar"
style="display: flex; justify-content: center"
>
<img
:src="user.avatar"
style="width: 5rem; height: 5rem; border-radius: 9999px"
/>
</div>
<!-- <pre>{{ user }}</pre> -->
<div>
<label for="avatar">Avatar</label>
<input
id="avatar"
type="file"
:class="{ 'border-danger': form.invalid('avatar') }"
@change="
(e) => {
const target = e.target as HTMLInputElement;
if (target.files) {
form.avatar = target.files[0];
}

form.forgetError('avatar');
}
"
/>
<span v-if="form.invalid('avatar')" class="text-danger">
{{ form.errors.avatar }}
</span>
</div>
<div>
<label for="name">Name</label>
<input id="name" v-model="form.name" type="text" />
<span v-if="errors.name">{{ errors.name[0] }}</span>
<input
id="name"
v-model="form.name"
type="text"
:class="{ 'border-danger': form.invalid('name') }"
@input="form.forgetError('name')"
/>
<span v-if="form.invalid('name')" class="text-danger">
{{ form.errors.name }}
</span>
</div>
<div>
<label for="email">Email</label>
<input id="email" v-model="form.email" type="text" />
<span v-if="errors.email">{{ errors.email[0] }}</span>
<input
id="email"
v-model="form.email"
type="text"
:class="{ 'border-danger': form.invalid('email') }"
@input="form.forgetError('email')"
/>
<span v-if="form.invalid('email')" class="text-danger">
{{ form.errors.email }}
</span>
</div>
<button type="submit">Save</button>
<button type="submit">{{ form.processing ? 'Saving' : 'Save' }}</button>
<button type="button" @click="resetForm">Reset</button>
</div>
</form>
</template>
Expand Down Expand Up @@ -102,4 +146,11 @@ onMounted(() => {
.profile-form button:hover {
background-color: #000;
}

.text-danger {
color: red;
}
.border-danger {
border: 1px solid red !important;
}
</style>
25 changes: 22 additions & 3 deletions src/runtime/composables/useSanctumFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,31 @@ import type {
MappedResponseType,
ResponseType,
} from 'ofetch';
import { useNuxtApp } from '#app';
import createFetchService from '../services/createFetchService';
import { createLogger } from '../helpers/createLogger';
import { useSanctumOptions } from './useSanctumOptions';
// import { useNuxtApp } from '#app';

export const useSanctumFetch = <T = any, R extends ResponseType = 'json'>(
request: FetchRequest,
options?: FetchOptions<R>,
): Promise<MappedResponseType<R, T>> => {
const { $sanctumFetch } = useNuxtApp();
return ($sanctumFetch as $Fetch)<T, R>(request, options);
// const { $sanctumFetch } = useNuxtApp();
// return ($sanctumFetch as $Fetch)<T, R>(request, options);

const { logLevel } = useSanctumOptions();
const logger = createLogger(logLevel);

// Extract onRequest and onResponseError from options
const { onRequest, onResponseError, ...otherOptions } = options || {};

// Pass only the necessary options to the fetch service
const fetchServiceOptions: FetchOptions = {
...(onRequest && { onRequest }),
...(onResponseError && { onResponseError }),
};

const fetchService: $Fetch = createFetchService(fetchServiceOptions, logger);

return fetchService(request, otherOptions);
};
Loading

0 comments on commit 8bbadb1

Please sign in to comment.