Open mhaidarhanif opened 1 year ago
Example on route:
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { getFirstAddress } from "~/models";
import { Debug, MapboxEmbed } from "~/components";
export async function loader() {
return json({
address: await getFirstAddress(),
});
}
export default function ExamplesMapboxRoute() {
const { address } = useLoaderData<typeof loader>();
if (!address) {
return <p>Address is not available</p>;
}
return (
<div className="space-y-8 p-4">
<h1>Example Mapbox</h1>
<section className="flex max-w-full gap-4">
<div>
<h2>With Address</h2>
<MapboxEmbed
address={address as any}
style={{ width: 500, height: 300 }}
draggable
/>
</div>
<div>
<Debug title="address" className="whitespace-pre-wrap">
{address}
</Debug>
</div>
</section>
<section>
<h2>Without Address</h2>
<MapboxEmbed draggable zoom={10} />
</section>
</div>
);
}
Usage on new address route:
import { redirect } from "@remix-run/node";
import { useActionData } from "@remix-run/react";
import {
ValidatedForm as RemixValidatedForm,
validationError,
} from "remix-validated-form";
import { withZod } from "@remix-validated-form/with-zod";
import type { DataFunctionArgs } from "@remix-run/node";
import {
Debug,
FormInput,
FormSubmitButton,
FormTextArea,
Link,
MapboxEmbed,
} from "~/components";
import { useRootLoaderData } from "~/hooks";
import { createNewAddressForUser, getFirstAddressByUser } from "~/models";
import { useState } from "react";
import { getUserRedirect } from "~/helpers";
import {
placeholderAddress,
defaultAddressCoordinate,
upsertAddressSchema,
} from "~/schema";
import type { AddressCoordinate } from "~/schema";
import { getRedirectTo, useRedirectTo } from "~/utils";
export const validator = withZod(upsertAddressSchema);
export const action = async ({ request }: DataFunctionArgs) => {
const redirectTo = getRedirectTo(request);
const userSession = await getUserRedirect(request);
const userId = userSession.id;
const result = await validator.validate(await request.formData());
if (result.error) return validationError(result.error);
const existingAdress = await getFirstAddressByUser({ userId });
const hasExistingAddress = Boolean(existingAdress?.id);
await createNewAddressForUser({
userId,
address: result.data as any,
isPrimary: Boolean(redirectTo || !hasExistingAddress),
// The new address will be set auomaticlaly as primary if:
// A. There is a redirect to searchParams
// B. There is no existing address yet
});
return redirect(redirectTo || "/user/addresses");
};
export default function AdminNewAddressRoute() {
const { ENV } = useRootLoaderData();
const actionData = useActionData<typeof action>();
const [coordinate, setCoordinate] = useState<AddressCoordinate>({
longitude: defaultAddressCoordinate.longitude,
latitude: defaultAddressCoordinate.latitude,
});
const handleChangeCoordinate = (newCoordinate: AddressCoordinate) => {
setCoordinate(newCoordinate);
};
const defaultValues =
ENV && ENV.NODE_ENV === "development" ? placeholderAddress : {};
const redirectTo = useRedirectTo();
const createAddressLinkText = redirectTo
? `Simpan dan Jadikan Alamat Utama`
: "Simpan Alamat";
const createAddressLinkLoadingText = redirectTo
? `Menyimpan dan Menjadikan Alamat Utama...`
: "Menyimpan Alamat...";
return (
<div className="space-y-4 rounded border bg-white p-4">
<header>
<h2>Tambah Alamat Tujuan Pengiriman</h2>
</header>
<main className="w-full max-w-xl basis-1/2">
<RemixValidatedForm
validator={validator}
method="post"
defaultValues={defaultValues}
className="space-y-8"
>
<section className="space-y-2">
<h3>Detail alamat</h3>
<div className="space-y-1">
<FormInput
name="name"
label="Nama Label Alamat"
placeholder="Rumah Utama"
/>
<p className="text-xs">
Hindari penamaan ambigu seperti "Rumah Saya", "Toko Saya", dan
sejenisnya.
</p>
<FormInput
name="street"
label="Jalan"
placeholder={placeholderAddress.street}
/>
<FormTextArea
name="streetDetails"
label="Detail Jalan"
placeholder={placeholderAddress.streetDetails}
rows={2}
/>
<div className="flex flex-wrap gap-2 md:flex-nowrap">
<FormInput
name="subDistrict"
label="Kelurahan"
placeholder={placeholderAddress.subDistrict}
className="grow md:basis-1/2"
/>
<FormInput
name="district"
label="Kecamatan"
placeholder={placeholderAddress.district}
className="grow md:basis-1/2"
/>
</div>
<div className="flex flex-wrap gap-2 md:flex-nowrap">
<FormInput
name="city"
label="Kota/Kabupaten"
placeholder={placeholderAddress.city}
className="grow md:basis-1/2"
/>
<FormInput
name="province"
label="Provinsi"
placeholder={placeholderAddress.province}
className="grow md:basis-1/2"
/>
</div>
<div className="flex flex-wrap gap-2 md:flex-nowrap">
<FormInput
name="postalCode"
label="Kode Pos"
placeholder={placeholderAddress.postalCode}
className="grow md:basis-1/2"
/>
<FormInput
name="countryCode"
label="Negara"
placeholder={placeholderAddress.countryCode}
className="grow md:basis-1/2"
disabled
/>
</div>
</div>
</section>
<section className="space-y-2">
<h3>Detail penerima</h3>
<div className="space-y-1">
<FormInput
name="recipientName"
label="Nama Penerima"
placeholder="Nona Wijaya"
/>
<FormInput
name="recipientPhone"
label="Nomor HP"
placeholder="0812 3456 7890"
/>
<p className="text-xs">
Nomor HP ini akan digunakan agar kurir dapat menghubungi
penerima/seseorang di lokasi tersebut. Boleh sama atau berbeda
dengan nomor HP di profil Anda.
</p>
</div>
<FormInput
name="notesForCourier"
label="Catatan untuk kurir (opsional)"
/>
</section>
<section className="space-y-2">
<h3>Titik lokasi (pinpoint)</h3>
{/* <div>
<label htmlFor="search-location">Cari lokasi</label>
<Input
id="search-location"
placeholder="Ketik nama kecamatan atau kelurahan..."
/>
</div> */}
<div className="space-y-1">
<MapboxEmbed
style={{ width: "100%", height: 300 }}
zoom={12}
draggable
coordinateValue={coordinate}
handleChangeCoordinate={handleChangeCoordinate}
/>
<Debug title="coordinate" className="max-w-xs">
{coordinate}
</Debug>
</div>
<div>
<input
hidden
type="number"
name="latitude"
value={coordinate.latitude}
readOnly
/>
<input
hidden
type="number"
name="longitude"
value={coordinate.longitude}
readOnly
/>
</div>
</section>
<section className="space-y-1">
<p className="text-sm">
Dengan menyimpan alamat, kamu menyetujui{" "}
<Link to="/terms" className="font-bold text-brand-500">
Syarat & Ketentuan
</Link>
</p>
<FormSubmitButton
loadingChildren={createAddressLinkLoadingText}
className="w-full"
>
{createAddressLinkText}
</FormSubmitButton>
</section>
</RemixValidatedForm>
</main>
<Debug title="actionData">{actionData}</Debug>
</div>
);
}