Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: domain-functions #3

Open
wants to merge 4 commits into
base: remix-forms
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/components/address/address-item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { AddressItemType } from '../../types/address'
import { UnpackData } from 'domain-functions'
import { getAddress } from '../../models/address'

type AddressItemProps = {
item: AddressItemType
item: UnpackData<typeof getAddress>['address'][number]
}
export function AddressItem({ item }: AddressItemProps) {
return (
Expand Down
5 changes: 3 additions & 2 deletions src/components/cart/cart-item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { CartItemType } from '../../types/cart'
import { UnpackData } from 'domain-functions'
import { getCart } from '../../models/cart'

type CartItemProps = {
item: CartItemType
item: UnpackData<typeof getCart>['cart']['items'][number]
}
export function CartItem({ item }: CartItemProps) {
return (
Expand Down
7 changes: 3 additions & 4 deletions src/components/cart/cart-summary.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { CartType } from '../../types/cart'
import { UnpackData } from 'domain-functions'
import { getCart } from '../../models/cart'
import { pluralize } from '../../utils/pluralize'

type CartSummaryProps = {
cart: CartType
}
type CartSummaryProps = UnpackData<typeof getCart>

export function CartSummary({ cart }: CartSummaryProps) {
return (
Expand Down
37 changes: 34 additions & 3 deletions src/models/address.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
export async function getAddress() {
return mockAddress
}
import { makeDomainFunction, pipe } from 'domain-functions'
import * as z from 'zod'

const addressItemSchema = z.object({
id: z.number(),
customerId: z.number(),
label: z.string(),
givenName: z.string(),
familyName: z.string(),
streetAddress: z.string(),
number: z.string(),
district: z.string(),
complement: z.string(),
postalCode: z.string(),
addressLocality: z.string(),
addressRegion: z.string(),
referencePoint: z.string().optional(),
localityCode: z.number(),
addressType: z.string().optional(),
main: z.boolean(),
billing: z.boolean(),
updatedAt: z.string(),
geolocation: z.object({ latitude: z.string(), longitude: z.string() }).optional(),
dependencyConnections: z.array(z.unknown()),
})

const getAddressItems = makeDomainFunction()(async () => mockAddress)
const normalizeAddresses = makeDomainFunction(z.object({ items: z.array(addressItemSchema) }))(
async ({ items: address }) => ({
address,
}),
)

export const getAddress = pipe(getAddressItems, normalizeAddresses)

const mockAddress = {
items: [
Expand Down
50 changes: 47 additions & 3 deletions src/models/cart.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,47 @@
export async function getCart() {
return await fetch('https://www.mocky.io/v2/5b15c4923100004a006f3c07').then((r) => r.json())
}
import { makeDomainFunction, pipe } from 'domain-functions'
import * as z from 'zod'

const imageObjectSchema = z.object({
featured: z.boolean(),
thumbnail: z.string(),
small: z.string(),
medium: z.string(),
large: z.string(),
extraLarge: z.string(),
valid: z.boolean(),
})

const priceSpecificationSchema = z.object({
sku: z.string(),
price: z.number(),
originalPrice: z.number(),
maxPrice: z.number(),
percent: z.number(),
discount: z.number(),
})

const cartItemSchema = z.object({
quantity: z.number(),
product: z.object({
sku: z.string(),
name: z.string(),
imageObjects: z.array(imageObjectSchema),
priceSpecification: priceSpecificationSchema,
}),
})

const cartSchema = z.object({
discount: z.number(),
id: z.string(),
items: z.array(cartItemSchema),
shippingTotal: z.number(),
subTotal: z.number(),
total: z.number(),
})

const fetchCart = makeDomainFunction()(() =>
fetch('https://www.mocky.io/v2/5b15c4923100004a006f3c07').then((r) => r.json()),
)
const normalizeCart = makeDomainFunction(cartSchema)(async (cart) => ({ cart }))

export const getCart = pipe(fetchCart, normalizeCart)
5 changes: 5 additions & 0 deletions src/models/compositions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { merge } from 'domain-functions'
import { getAddress } from './address'
import { getCart } from './cart'

export const getAddressRouteData = merge(getCart, getAddress)
10 changes: 6 additions & 4 deletions src/models/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export async function getConfig() {
return {
import { makeDomainFunction } from 'domain-functions'

export const getConfig = makeDomainFunction()(async () => ({
config: {
organizationId: 1,
organization: 'blzstore',
name: 'Beleza Na Web',
}
}
},
}))
18 changes: 9 additions & 9 deletions src/models/payment.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { makeDomainFunction } from 'domain-functions'
import { z } from 'zod'
import { PaymentType } from '../types/payment'

export async function makePayment(payload: PaymentType) {
export const schema = z.object({
card: z.string().min(18, 'Informe um número de cartão de crédito'),
name: z.string().min(1, 'Informe um títular'),
expire: z.string().min(1),
})

export const makePayment = makeDomainFunction(schema)(async (input) => {
await new Promise((res) => setTimeout(res, 3000))

// api.post()
console.log(payload)
console.log(input)

return true
}

export const schema = z.object({
card: z.string().min(18, 'Informe um número de cartão de crédito'),
name: z.string().min(1, 'Informe um títular'),
expire: z.string().min(1),
})
36 changes: 10 additions & 26 deletions src/routes/address.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,27 @@
import {
useLoaderData,
useRouteLoaderData,
json,
Form,
useSubmit,
ActionFunctionArgs,
Link,
} from 'react-router-dom'
import { inputFromForm, UnpackData } from 'domain-functions'
import { useLoaderData, Form, useSubmit, ActionFunctionArgs, Link } from 'react-router-dom'
import { AddressItem } from '../components/address'
import { Box } from '../components/box'
import type { AddressType } from '../types/address'
import { getAddress } from '../models/address'
import { getCart } from '../models/cart'
import type { CartType } from '../types/cart'
import { getAddressRouteData } from '../models/compositions'
import { loaderResponseOrNotFound } from '../utils/responses'

export async function loader() {
const [cart, address] = await Promise.all([getCart(), getAddress()])

return json({ cart, address })
const result = await getAddressRouteData()
return loaderResponseOrNotFound(result)
}

export async function action({ request }: ActionFunctionArgs) {
const formData = Object.fromEntries(await request.formData())
const formData = await inputFromForm(request)
console.log(formData)

// await useAddress(formData.address)
return {} // redirect('transacional/pagamento')
}

type DataLoader = {
address: AddressType
cart: CartType
}

export default function Address() {
const data = useLoaderData() as DataLoader
const config = useRouteLoaderData('root')
// console.log({ config, data })
const { address, cart } = useLoaderData() as UnpackData<typeof getAddressRouteData>
const submit = useSubmit()
console.log(cart)

return (
<div style={{ display: 'flex', gap: '16px' }}>
Expand All @@ -49,7 +33,7 @@ export default function Address() {
submit(event.currentTarget)
}}
>
{data.address.items.map((item) => (
{address.map((item) => (
<AddressItem key={item.label} item={item} />
))}
</Form>
Expand Down
20 changes: 9 additions & 11 deletions src/routes/cart.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
import { ActionFunctionArgs, json, Link, useLoaderData, useRouteLoaderData } from 'react-router-dom'
import { ActionFunctionArgs, Link, useLoaderData, useRouteLoaderData } from 'react-router-dom'
import { Box } from '../components/box'
import { CartItem } from '../components/cart'
import type { CartType } from '../types/cart'
import { getCart } from '../models/cart'
import { pluralize } from '../utils/pluralize'
import { inputFromForm, UnpackData } from 'domain-functions'
import { loaderResponseOrNotFound } from '../utils/responses'
import { getConfig } from '../models/config'

export async function loader() {
const cart = await getCart()

return json(cart)
const result = await getCart()
return loaderResponseOrNotFound(result)
}

export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData()
const formData = await inputFromForm(request)
console.log(formData)

return null
}

type LoaderData = CartType

export default function Cart() {
const cart = useLoaderData() as LoaderData
const config = useRouteLoaderData('root')
const { cart } = useLoaderData() as UnpackData<typeof getCart>
const { config } = useRouteLoaderData('root') as UnpackData<typeof getConfig>
const cartLength = cart.items.length
console.log(config)

return (
<div style={{ display: 'flex', gap: '16px' }}>
Expand Down
27 changes: 9 additions & 18 deletions src/routes/payment.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
import { useLoaderData, useRouteLoaderData, json, useNavigation, ActionFunction } from 'react-router-dom'
import { makeDomainFunction } from 'domain-functions'
import { useLoaderData, useNavigation, ActionFunction } from 'react-router-dom'
import { UnpackData } from 'domain-functions'
import { formAction, Form } from '../components/form'

import { Box } from '../components/box'
import { CartSummary } from '../components/cart'
import type { AddressType } from '../types/address'
import { getAddress } from '../models/address'
import type { CartType } from '../types/cart'
import { getCart } from '../models/cart'
import { makePayment, schema } from '../models/payment'
import { getAddressRouteData } from '../models/compositions'
import { loaderResponseOrNotFound } from '../utils/responses'

export async function loader() {
const [cart, address] = await Promise.all([getCart(), getAddress()])
return json({ cart, address })
const result = await getAddressRouteData()
return loaderResponseOrNotFound(result)
}

const mutation = makeDomainFunction(schema)(async (values) => await makePayment(values))

export const action: ActionFunction = async ({ request }) =>
formAction({
request,
schema,
mutation,
mutation: makePayment,
successPath: '../transacional/sucesso',
})

type DataLoader = {
address: AddressType
cart: CartType
}

export default function Address() {
const data = useLoaderData() as DataLoader
const { cart } = useLoaderData() as UnpackData<typeof getAddressRouteData>
const navigation = useNavigation()
const isPending = navigation.state === 'submitting'

Expand All @@ -54,7 +45,7 @@ export default function Address() {
<button type="submit" className="btn" style={{ marginBlock: 10 }} form="payment">
{isPending ? 'Pagando...' : 'Finalizar Pedido'}
</button>
<CartSummary cart={data.cart} />
<CartSummary cart={cart} />
</aside>
</fieldset>
)
Expand Down
10 changes: 5 additions & 5 deletions src/routes/root.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Link, Outlet, useLoaderData } from 'react-router-dom'
import { Container } from '../components/container'
import type { Config } from '../types/config'
import { getConfig } from '../models/config'
import { loaderResponseOrNotFound } from '../utils/responses'
import { UnpackData } from 'domain-functions'

export async function loader() {
return await getConfig()
const result = await getConfig()
return loaderResponseOrNotFound(result)
}

type LoaderData = Config

export default function Root() {
const config = useLoaderData() as LoaderData
const { config } = useLoaderData() as UnpackData<typeof getConfig>

return (
<>
Expand Down
25 changes: 0 additions & 25 deletions src/types/address.ts

This file was deleted.

Loading