-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* init api * created product-slider * created stores * renamed to svelte-shop
- Loading branch information
1 parent
223644d
commit 524e0c7
Showing
31 changed files
with
612 additions
and
43 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
}, | ||
"type": "module", | ||
"dependencies": { | ||
"immer": "^10.0.4" | ||
"immer": "^10.0.4", | ||
"validate": "^5.2.0" | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
32 changes: 32 additions & 0 deletions
32
packages/svelte-example-shop/src/lib/components/ProductSlider.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<script lang="ts"> | ||
import createProductStore from "$lib/stores/products" | ||
export let name:string | ||
const productsStore = createProductStore(name) | ||
const hits = productsStore.useState(state => state.data) | ||
</script> | ||
|
||
<div class='ProductSlider'> | ||
{#each $hits as hit} | ||
<div class="product"> | ||
<h2>{hit.name}</h2> | ||
<p>{hit.price}€</p> | ||
</div> | ||
{/each} | ||
</div> | ||
|
||
|
||
<style> | ||
.ProductSlider { | ||
display: flex; | ||
flex-wrap: wrap; | ||
gap: 20px; | ||
} | ||
.product { | ||
width: 200px; | ||
border: 1px solid #ccc; | ||
padding: 1rem; | ||
} | ||
</style> |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import createStore from "@rlx/svelte"; | ||
import { Customer } from "../../server-state"; | ||
|
||
declare global { | ||
interface RlxStores { | ||
account: ReturnType<typeof createAccountStore> | ||
} | ||
} | ||
|
||
export default function createAccountStore () { | ||
const store = createStore({ | ||
name: 'account', | ||
persist: true, | ||
state: { | ||
user: null as Customer | null, | ||
initialFetched: false, | ||
fetchError: null as string | null, | ||
isLoggingIn: false, | ||
}, | ||
actions: { | ||
/** comment */ | ||
initialFetch: () => ({ | ||
triggerOnMount: true, | ||
fetcher: () => fetch('/api/account'), | ||
mapResponse: r => ({ user: r, initialFetched: true }), | ||
}), | ||
login: (email: string, password: string) => ({ | ||
fetcher: () => fetch('/api/account/login', { email, password }), | ||
concurrency: 'FIRST', | ||
mappings: { data: 'user', isFetching: 'isLoggingIn'} | ||
}), | ||
logout: () => ({ | ||
fetcher: () => fetch('/api/account/logout').then(r => r.json()), | ||
concurrency: 'FIRST', | ||
optimisticData: () => ({ user: null }), | ||
}), | ||
register: (email: string, password: string) => ({ | ||
fetcher: () => fetch('/api/account/register', { email, password }), | ||
concurrency: 'FIRST', | ||
mappings: { data: 'user' } | ||
}), | ||
updateUser: (user:{name:string}) => ({ | ||
fetcher: () => fetch('/api/account/update', user), | ||
optimisticData: (state) => ({ user: {...state.user, ...user} }), | ||
concurrency: 'LAST', | ||
mappings: { data: 'user' } | ||
}), | ||
} | ||
}) | ||
|
||
store.addRule({ | ||
id: 'log-user', | ||
target: 'account/login/request', | ||
consequence: ({action, store}) => store.actions.initialFetch() | ||
}) | ||
|
||
return store | ||
} | ||
|
||
function fetch(url: string, body:any=null) { | ||
return window.fetch(url, { | ||
method: 'POST', | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: JSON.stringify(body) | ||
}).then(r => r.json()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import createStore from "@rlx/svelte"; | ||
|
||
export type Channel = 'b2b' | 'b2c' | ||
|
||
export default function createChannelStore() { | ||
const store = createStore({ | ||
name: 'channel', | ||
persist: true, | ||
state: { | ||
data: 'b2b' as Channel | ||
}, | ||
actions: { | ||
set: (channel: Channel) => state => ({data:channel}) | ||
} | ||
}) | ||
|
||
store.addRule({ | ||
id: 'log-set', | ||
target: ['account/login/success', 'account/initialFetch/success'], | ||
consequence: ({store}) => store.actions.set('b2b') | ||
}) | ||
|
||
return store | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import createStore from "@rlx/svelte" | ||
import type { Product } from "../../server-state" | ||
|
||
export type FilterValues = { | ||
search: string | ||
color: string | ||
} | ||
|
||
declare global { | ||
interface RlxStores { | ||
products: ReturnType<typeof createProductStore> | ||
} | ||
} | ||
|
||
export default function createProductStore(name:string, filterValues: Partial<FilterValues> = {}) { | ||
const store = createStore({ | ||
name: 'products', | ||
key: name, | ||
state: { | ||
data: [] as Product[], | ||
isFetching: false, | ||
fetchError: null as string | null, | ||
filterValues: { | ||
search: '', | ||
color: '', | ||
...filterValues | ||
} satisfies FilterValues as FilterValues | ||
}, | ||
actions: { | ||
fetch: () => ({ | ||
triggerOnMount: true, | ||
concurrency: 'SWITCH', | ||
fetcher: state => fetchProducts(state.filterValues), | ||
mapResponse: (response, state) => ({ | ||
...state, | ||
data: response.hits, | ||
isFetching: false, | ||
}) | ||
}), | ||
/** my comment */ | ||
setFilterValue: (key: keyof FilterValues, value: string) => state => ({ | ||
filterValues: { | ||
...state.filterValues, | ||
[key]: value | ||
} | ||
}) | ||
} | ||
}) | ||
|
||
store.addRule({ | ||
id: 'trigger-fetch', | ||
target: '/setFilterValue', | ||
consequence: (args) => args.store.actions.fetch() | ||
}) | ||
|
||
return store | ||
} | ||
|
||
async function fetchProducts(filterValues: FilterValues) { | ||
const url = new URL('/api/products', window.location.href) | ||
|
||
const body = JSON.stringify(filterValues) | ||
|
||
return fetch(url, {method: 'POST', body}).then(res => res.json()) as Promise<{ | ||
hits: Product[] | ||
}> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<script lang="ts"> | ||
import ProductSlider from "$lib/components/ProductSlider.svelte"; | ||
</script> | ||
|
||
|
||
<ProductSlider name='home-slider-1'/> |
10 changes: 10 additions & 0 deletions
10
packages/svelte-example-shop/src/routes/api/account/+server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import serverState, { type Customer } from '../../../server-state.js'; | ||
import Schema from 'validate' | ||
|
||
/** @type {import('./$types').RequestHandler} */ | ||
export async function POST (params) { | ||
|
||
const customer = serverState.customers.find(c => c.email === serverState.currentCustomerId) ?? null | ||
|
||
return new Response(JSON.stringify(customer)) | ||
} |
37 changes: 37 additions & 0 deletions
37
packages/svelte-example-shop/src/routes/api/account/login/+server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import serverState, { type Customer } from '../../../../server-state.js'; | ||
import Schema from 'validate' | ||
|
||
const schema = new Schema({ | ||
email: { | ||
type: 'string', | ||
required: true | ||
}, | ||
password: { | ||
type: 'string', | ||
required: true | ||
} | ||
}) | ||
|
||
/** @type {import('./$types').RequestHandler} */ | ||
export async function POST (params) { | ||
const body = await params.request.json() as { | ||
email: string | ||
password: string | ||
} | ||
|
||
const errors = schema.validate(body) | ||
if (errors.length) { | ||
return new Response(JSON.stringify(errors), { status: 400 }) | ||
} | ||
|
||
const customer = serverState.customers.find(c => c.email === body.email) | ||
|
||
if (!customer) { | ||
return new Response(JSON.stringify({error: 'Customer does not exist'}), { status: 400 }) | ||
} | ||
|
||
serverState.customers.push(customer) | ||
serverState.currentCustomerId = customer.id | ||
|
||
return new Response(JSON.stringify(customer)) | ||
} |
42 changes: 42 additions & 0 deletions
42
packages/svelte-example-shop/src/routes/api/account/register/+server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import serverState, { type Customer } from '../../../../server-state.js'; | ||
import Schema from 'validate' | ||
|
||
const schema = new Schema({ | ||
email: { | ||
type: 'string', | ||
required: true | ||
}, | ||
password: { | ||
type: 'string', | ||
required: true | ||
} | ||
}) | ||
|
||
/** @type {import('./$types').RequestHandler} */ | ||
export async function POST (params) { | ||
const body = await params.request.json() as { | ||
email: string | ||
password: string | ||
} | ||
|
||
const errors = schema.validate(body) | ||
if (errors.length) { | ||
return new Response(JSON.stringify(errors), { status: 400 }) | ||
} | ||
|
||
if (serverState.customers.find(c => c.email === body.email)) { | ||
return new Response(JSON.stringify({error: 'Customer already exists'}), { status: 400 }) | ||
} | ||
|
||
const customer:Customer = { | ||
email: body.email, | ||
password: body.password, | ||
id: Math.random().toString(36).substring(7), | ||
name: 'INITIAL' | ||
} | ||
|
||
serverState.customers.push(customer) | ||
serverState.currentCustomerId = customer.id | ||
|
||
return new Response(JSON.stringify(customer)) | ||
} |
35 changes: 35 additions & 0 deletions
35
packages/svelte-example-shop/src/routes/api/account/update/+server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import serverState, { type Customer } from '../../../../server-state.js'; | ||
import Schema from 'validate' | ||
|
||
const schema = new Schema({ | ||
name: { | ||
type: 'string', | ||
required: false | ||
}, | ||
}) | ||
|
||
/** @type {import('./$types').RequestHandler} */ | ||
export async function POST (params) { | ||
const body = await params.request.json() as { | ||
name?: string | ||
} | ||
|
||
const errors = schema.validate(body) | ||
if (errors.length) { | ||
return new Response(JSON.stringify(errors), { status: 400 }) | ||
} | ||
|
||
if(serverState.currentCustomerId === null) { | ||
return new Response(JSON.stringify({error: 'Not logged in'}), { status: 401 }) | ||
} | ||
|
||
const customer = serverState.customers.find(c => c.id === serverState.currentCustomerId) | ||
|
||
if (!customer) { | ||
return new Response(JSON.stringify({error: 'Customer does not exist'}), { status: 400 }) | ||
} | ||
|
||
if(body.name) customer.name = body.name | ||
|
||
return new Response(JSON.stringify(customer)) | ||
} |
10 changes: 10 additions & 0 deletions
10
packages/svelte-example-shop/src/routes/api/cart/+server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import serverState, { type Customer } from '../../../server-state.js'; | ||
import Schema from 'validate' | ||
|
||
/** @type {import('./$types').RequestHandler} */ | ||
export async function POST (params) { | ||
|
||
const cart = serverState.cart | ||
|
||
return new Response(JSON.stringify(cart)) | ||
} |
38 changes: 38 additions & 0 deletions
38
packages/svelte-example-shop/src/routes/api/cart/add-item/+server.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import serverState from '../../../../server-state.js'; | ||
import Schema from 'validate' | ||
|
||
const schema = new Schema({ | ||
productID: { | ||
type: 'string', | ||
required: true | ||
}, | ||
amount: { | ||
type: 'number', | ||
required: true | ||
} | ||
}) | ||
|
||
/** @type {import('./$types').RequestHandler} */ | ||
export async function POST (params) { | ||
const body = await params.request.json() as { productID: string, amount: number } | ||
|
||
const errors = schema.validate(body) | ||
if (errors.length) { | ||
return new Response(JSON.stringify(errors), { status: 400 }) | ||
} | ||
|
||
if (serverState.cart.find(item => item.productID === body.productID)) { | ||
serverState.cart = serverState.cart.map(item => { | ||
if (item.productID === body.productID) { | ||
item.amount += body.amount | ||
} | ||
return item | ||
}) | ||
} | ||
else { | ||
serverState.cart.push(body) | ||
} | ||
|
||
|
||
return new Response(JSON.stringify(serverState.cart)) | ||
} |
Oops, something went wrong.