diff options
Diffstat (limited to 'examples/ssr/src')
-rw-r--r-- | examples/ssr/src/api.ts | 51 | ||||
-rw-r--r-- | examples/ssr/src/components/AddToCart.svelte | 9 | ||||
-rw-r--r-- | examples/ssr/src/components/Cart.svelte | 6 | ||||
-rw-r--r-- | examples/ssr/src/components/Header.astro | 20 | ||||
-rw-r--r-- | examples/ssr/src/models/user.ts | 8 | ||||
-rw-r--r-- | examples/ssr/src/pages/cart.astro | 47 | ||||
-rw-r--r-- | examples/ssr/src/pages/login.astro | 30 | ||||
-rw-r--r-- | examples/ssr/src/pages/login.form.js | 10 | ||||
-rw-r--r-- | examples/ssr/src/pages/products/[id].astro | 2 |
9 files changed, 174 insertions, 9 deletions
diff --git a/examples/ssr/src/api.ts b/examples/ssr/src/api.ts index 59619ade6..b71990f3f 100644 --- a/examples/ssr/src/api.ts +++ b/examples/ssr/src/api.ts @@ -5,12 +5,25 @@ interface Product { image: string; } -//let origin: string; -const { mode } = import.meta.env; -const origin = mode === 'develepment' ? `http://localhost:3000` : `http://localhost:8085`; +interface User { + id: number; +} + +interface Cart { + items: Array<{ + id: number; + name: string; + count: number; + }>; +} + +const { MODE } = import.meta.env; +const origin = MODE === 'development' ? `http://127.0.0.1:3000` : `http://127.0.0.1:8085`; async function get<T>(endpoint: string, cb: (response: Response) => Promise<T>): Promise<T> { - const response = await fetch(`${origin}${endpoint}`); + const response = await fetch(`${origin}${endpoint}`, { + credentials: 'same-origin' + }); if (!response.ok) { // TODO make this better... return null; @@ -31,3 +44,33 @@ export async function getProduct(id: number): Promise<Product> { return product; }); } + +export async function getUser(): Promise<User> { + return get<User>(`/api/user`, async response => { + const user: User = await response.json(); + return user; + }); +} + +export async function getCart(): Promise<Cart> { + return get<Cart>(`/api/cart`, async response => { + const cart: Cart = await response.json(); + return cart; + }); +} + +export async function addToUserCart(id: number | string, name: string): Promise<void> { + await fetch(`${origin}/api/add-to-cart`, { + credentials: 'same-origin', + method: 'POST', + mode: 'no-cors', + headers: { + 'Content-Type': 'application/json', + 'Cache': 'no-cache' + }, + body: JSON.stringify({ + id, + name + }) + }); +} diff --git a/examples/ssr/src/components/AddToCart.svelte b/examples/ssr/src/components/AddToCart.svelte index b03b8180a..0f7a97a93 100644 --- a/examples/ssr/src/components/AddToCart.svelte +++ b/examples/ssr/src/components/AddToCart.svelte @@ -1,11 +1,18 @@ <script> + import { addToUserCart } from '../api'; export let id = 0; + export let name = ''; - function addToCart() { + function notifyCartItem(id) { window.dispatchEvent(new CustomEvent('add-to-cart', { detail: id })); } + + async function addToCart() { + await addToUserCart(id, name); + notifyCartItem(id); + } </script> <style> button { diff --git a/examples/ssr/src/components/Cart.svelte b/examples/ssr/src/components/Cart.svelte index 63dd1b5a5..74db0bc79 100644 --- a/examples/ssr/src/components/Cart.svelte +++ b/examples/ssr/src/components/Cart.svelte @@ -12,6 +12,8 @@ .cart { display: flex; align-items: center; + text-decoration: none; + color: inherit; } .cart :first-child { margin-right: 5px; @@ -26,7 +28,7 @@ } </style> <svelte:window on:add-to-cart={onAddToCart}/> -<div class="cart"> +<a href="/cart" class="cart"> <span class="material-icons cart-icon">shopping_cart</span> <span class="count">{count}</span> -</div> +</a> diff --git a/examples/ssr/src/components/Header.astro b/examples/ssr/src/components/Header.astro index 2839c70d3..c4d925a5f 100644 --- a/examples/ssr/src/components/Header.astro +++ b/examples/ssr/src/components/Header.astro @@ -1,6 +1,10 @@ --- import TextDecorationSkip from './TextDecorationSkip.astro'; import Cart from './Cart.svelte'; +import { getCart } from '../api'; + +const cart = await getCart(); +const cartCount = cart.items.reduce((sum, item) => sum + item.count, 0); --- <style> @import url('https://fonts.googleapis.com/css2?family=Lobster&display=swap'); @@ -21,11 +25,25 @@ import Cart from './Cart.svelte'; color: inherit; text-decoration: none; } + + .right-pane { + display: flex; + } + + .material-icons { + font-size: 36px; + margin-right: 1rem; + } </style> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <header> <h1><a href="/"><TextDecorationSkip text="Online Store" /></a></h1> <div class="right-pane"> - <Cart client:idle /> + <a href="/login"> + <span class="material-icons"> + login + </span> + </a> + <Cart client:idle count={cartCount} /> </div> </header> diff --git a/examples/ssr/src/models/user.ts b/examples/ssr/src/models/user.ts new file mode 100644 index 000000000..ecd839d46 --- /dev/null +++ b/examples/ssr/src/models/user.ts @@ -0,0 +1,8 @@ +import lightcookie from 'lightcookie'; + + +export function isLoggedIn(request: Request): boolean { + const cookie = request.headers.get('cookie'); + const parsed = lightcookie.parse(cookie); + return 'user-id' in parsed; +} diff --git a/examples/ssr/src/pages/cart.astro b/examples/ssr/src/pages/cart.astro new file mode 100644 index 000000000..e4a00183e --- /dev/null +++ b/examples/ssr/src/pages/cart.astro @@ -0,0 +1,47 @@ +--- +import Header from '../components/Header.astro'; +import Container from '../components/Container.astro'; +import { getCart } from '../api'; +import { isLoggedIn } from '../models/user'; + +if(!isLoggedIn(Astro.request)) { + return Astro.redirect('/'); +} + +// They must be logged in. + +const user = { name: 'test'}; // getUser? +const cart = await getCart(); +--- +<html> +<head> + <title>Cart | Online Store</title> + <style> + h1 { + font-size: 36px; + } + </style> +</head> +<body> + <Header /> + + <Container tag="main"> + <h1>Cart</h1> + <p>Hi { user.name }! Here are your cart items:</p> + <table> + <thead> + <tr> + <th>Item</th> + <th>Count</th> + </tr> + </thead> + <tbody> + {cart.items.map(item => <tr> + <td>{item.name}</td> + <td>{item.count}</td> + </tr>)} + </tbody> + </table> + </Container> +</body> +</html> diff --git a/examples/ssr/src/pages/login.astro b/examples/ssr/src/pages/login.astro new file mode 100644 index 000000000..b12a82a5e --- /dev/null +++ b/examples/ssr/src/pages/login.astro @@ -0,0 +1,30 @@ +--- +import Header from '../components/Header.astro'; +import Container from '../components/Container.astro'; +--- +<html> +<head> + <title>Online Store</title> + <style> + h1 { + font-size: 36px; + } + </style> +</head> +<body> + <Header /> + + <Container tag="main"> + <h1>Login</h1> + <form action="/login.form" method="POST"> + <label for="name">Name</label> + <input type="text" name="name"> + + <label for="password">Password</label> + <input type="password" name="password"> + + <input type="submit" value="Submit"> + </form> + </Container> +</body> +</html> diff --git a/examples/ssr/src/pages/login.form.js b/examples/ssr/src/pages/login.form.js new file mode 100644 index 000000000..9875ae160 --- /dev/null +++ b/examples/ssr/src/pages/login.form.js @@ -0,0 +1,10 @@ + +export function post(params, request) { + return new Response(null, { + status: 301, + headers: { + 'Location': '/', + 'Set-Cookie': 'user-id=1; Path=/; Max-Age=2592000' + } + }); +} diff --git a/examples/ssr/src/pages/products/[id].astro b/examples/ssr/src/pages/products/[id].astro index 943f2ab84..9c400c2f1 100644 --- a/examples/ssr/src/pages/products/[id].astro +++ b/examples/ssr/src/pages/products/[id].astro @@ -45,7 +45,7 @@ const product = await getProduct(id); <figure> <img src={product.image} /> <figcaption> - <AddToCart id={id} client:idle /> + <AddToCart client:idle id={id} name={product.name} /> <p>Description here...</p> </figcaption> </figure> |