@lessy-js/client
v1.0.22
Published
A react client for Lessy, a Headless CMS Platform.
Readme
@lessy-js/client
@lessy-js/client is a lightweight React library for easily integrating with Lessy, a headless CMS and e-commerce platform. Fetch pages, sections, products, manage customer authentication, addresses, and orders with minimal setup using intuitive hooks and a configurable client.
Installation
# NPM
npm install @lessy-js/client
# Yarn
yarn add @lessy-js/client
# PNPM
pnpm add @lessy-js/clientQuick Start
Initialize your CMS client at the root of your app:
import React from "react"; import { initLessy } from "@lessy-js/client"; // This should run once, e.g., in App.js or index.js initLessy({ apiKey: "YOUR_CMS_API_KEY", baseUrl: "https://api.lessy.in/public", // Optional, defaults to this token: null, // Optional, can be set later via useAuth hook });Use hooks to fetch pages or sections anywhere in your component tree:
import React from "react"; import { usePages, useSections } from "@lessy-js/client"; function PageList() { const { project, pages, loading, error } = usePages(); if (loading) return <p>Loading pages...</p>; if (error) return <p>Error: {error.message}</p>; return ( <> <h1> #{project.id} - {project.name} </h1> <ul> {pages.map((page) => ( <li key={page.pageId}> {page.pageId} - {page.pageName} </li> ))} </ul> </> ); } function SectionList({ pageId }) { const { sections, loading, error } = useSections(pageId); if (loading) return <p>Loading sections...</p>; if (error) return <p>Error: {error.message}</p>; return ( <ul> {sections.map((sec) => ( <li key={sec.sectionId}>{sec.sectionType}</li> ))} </ul> ); } export default function App() { return ( <div> <h1>My Lessy-driven Site</h1> <PageList /> <h2>Sections of Page 1</h2> <SectionList pageId={1} /> </div> ); }
Table of Contents
- Configuration
- Content & Pages Hooks
- Authentication Hooks
- Product Hooks
- Address Hooks
- Order Hooks
- Client API
- Examples
Configuration
initLessy(config)
Initialize the Lessy client with your configuration. This should be called once at the root of your application.
Parameters:
apiKey(required): Your project's API keybaseUrl(optional): API base URL (default:'https://api.lessy.in/public')token(optional): Initial customer JWT token for authenticated requests
Example:
import { initLessy } from "@lessy-js/client";
initLessy({
apiKey: "your-api-key-here",
baseUrl: "https://api.lessy.in/public", // Optional
});Content & Pages Hooks
usePages()
Fetches all pages for the project.
Returns:
project: Project information objectpages: Array of page objectsloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { project, pages, loading, error } = usePages();useSections(pageId)
Fetches all sections for a specific page.
Parameters:
pageId(required): Page ID to fetch sections for
Returns:
sections: Array of section objectsloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { sections, loading, error } = useSections(1);useSectionById(pageId, sectionId)
Gets a specific section by its ID.
Parameters:
pageId(required): Page IDsectionId(required): Section ID
Returns:
section: Section object or nullloading: Boolean indicating loading stateerror: Error object if request failed
useSectionContentItems(pageId, sectionId?)
Extracts all content items from sections, optionally filtered by section ID.
Parameters:
pageId(required): Page IDsectionId(optional): Section ID to filter by
Returns:
contentItems: Array of content itemsloading: Boolean indicating loading stateerror: Error object if request failed
useContentItemsByType(pageId, type)
Extracts all content items of a specific type from all sections.
Parameters:
pageId(required): Page IDtype(required): Content item type
Returns:
items: Array of content items matching the typeloading: Boolean indicating loading stateerror: Error object if request failed
useContentItem(pageId, sectionId, type, index?)
Gets a specific content item by section, type, and index.
Parameters:
pageId(required): Page IDsectionId(required): Section IDtype(required): Content item typeindex(optional): Index of the content item (default: 0)
Returns:
content: Content object or nullloading: Boolean indicating loading stateerror: Error object if request failed
useDemoContents(template?)
Fetches demo contents for a template.
Parameters:
template(optional): Template name
Returns:
data: Demo contents dataloading: Boolean indicating loading stateerror: Error object if request failed
Authentication Hooks
useSendOTP()
Sends an OTP to a customer's phone number.
Returns:
sendOTP: Function to send OTPloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { sendOTP, loading, error } = useSendOTP();
const handleSendOTP = async () => {
try {
await sendOTP({
country_code: "+1",
phone_number: "234567890",
name: "John Doe", // Optional
});
} catch (err) {
console.error("Failed to send OTP:", err);
}
};useVerifyOTP()
Verifies an OTP and returns a customer token.
Returns:
verifyOTP: Function to verify OTPloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { verifyOTP, loading, error } = useVerifyOTP();
const { setToken } = useAuth();
const handleVerifyOTP = async () => {
try {
const result = await verifyOTP({
country_code: "+1",
phone_number: "234567890",
otp: "123456",
});
// Token is automatically set in the client
setToken(result.token, result.customer);
} catch (err) {
console.error("Failed to verify OTP:", err);
}
};useAuth()
Manages authentication state and token.
Returns:
customer: Customer object or nulltoken: JWT token string or nullisAuthenticated: Boolean indicating authentication statussetToken: Function to set the token and customer dataclearAuth: Function to clear authentication
Example:
const { customer, token, isAuthenticated, setToken, clearAuth } = useAuth();
if (isAuthenticated) {
return <div>Welcome, {customer.name}!</div>;
}Product Hooks
useProducts(options?)
Fetches products with pagination.
Parameters:
options(optional): Object withpageandlimitpropertiespage(default: 1): Page numberlimit(default: 10): Number of products per page
Returns:
products: Array of product objectspagination: Pagination metadata objectloading: Boolean indicating loading stateerror: Error object if request failedrefetch: Function to refetch products
Example:
const { products, pagination, loading, error, refetch } = useProducts({
page: 1,
limit: 20,
});Customer Hooks
useUpdateCustomer()
Edit cuatomer name
Parameters:
id(required): CustomerId
Returns:
updateCustomer: Address object or nullloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { updateCustomer, loading, error } = useUpdateCustomer();Address Hooks
useAddresses()
Fetches all addresses for the authenticated customer.
Returns:
addresses: Array of address objectsloading: Boolean indicating loading stateerror: Error object if request failedrefetch: Function to refetch addresses
Example:
const { addresses, loading, error, refetch } = useAddresses();useAddress(addressId)
Fetches a specific address by ID.
Parameters:
addressId(required): Address ID
Returns:
address: Address object or nullloading: Boolean indicating loading stateerror: Error object if request failedrefetch: Function to refetch the address
useCreateAddress()
Creates a new address.
Returns:
createAddress: Function to create an addressloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { createAddress, loading, error } = useCreateAddress();
const { refetch } = useAddresses();
const handleCreateAddress = async () => {
try {
await createAddress({
address: "123 Main St",
city: "New York",
state: "NY",
postal_code: "10001",
country: "USA",
is_default: false,
label: "Home",
});
refetch(); // Refresh addresses list
} catch (err) {
console.error("Failed to create address:", err);
}
};useUpdateAddress()
Updates an existing address.
Returns:
updateAddress: Function to update an addressloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { updateAddress, loading, error } = useUpdateAddress();
const handleUpdateAddress = async (addressId) => {
try {
await updateAddress(addressId, {
address: "456 Oak Ave",
city: "Los Angeles",
is_default: true,
});
} catch (err) {
console.error("Failed to update address:", err);
}
};useDeleteAddress()
Deletes an address.
Returns:
deleteAddress: Function to delete an addressloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { deleteAddress, loading, error } = useDeleteAddress();
const { refetch } = useAddresses();
const handleDeleteAddress = async (addressId) => {
try {
await deleteAddress(addressId);
refetch(); // Refresh addresses list
} catch (err) {
console.error("Failed to delete address:", err);
}
};Order Hooks
useCheckout()
Creates a new order (checkout).
Returns:
checkout: Function to create an orderloading: Boolean indicating loading stateerror: Error object if request failed
Example:
const { checkout, loading, error } = useCheckout();
const handleCheckout = async () => {
try {
const order = await checkout({
items: [
{ product_id: 5, quantity: 2 },
{ product_id: 7, quantity: 1 },
],
address_id: 1,
notes: "Special delivery instructions",
currency: "USD",
});
console.log("Order created:", order.order_number);
} catch (err) {
console.error("Failed to checkout:", err);
}
};useOrders()
Fetches all orders for the authenticated customer.
Returns:
orders: Array of order objectsloading: Boolean indicating loading stateerror: Error object if request failedrefetch: Function to refetch orders
Example:
const { orders, loading, error, refetch } = useOrders();useOrder(orderNumber)
Fetches a specific order by order number.
Parameters:
orderNumber(required): Order number (e.g., "ORD-2025-001")
Returns:
order: Order object or nullloading: Boolean indicating loading stateerror: Error object if request failedrefetch: Function to refetch the order
Example:
const { order, loading, error } = useOrder("ORD-2025-001");Client API
If you prefer using the client directly instead of hooks, you can use the createClient function:
import { createClient } from "@lessy-js/client";
const client = createClient({
apiKey: "your-api-key",
baseUrl: "https://api.lessy.in/public",
token: "optional-initial-token",
});
// Set token later
client.setToken("customer-jwt-token");
// Use client methods
const pages = await client.fetchPages();
const products = await client.fetchProducts({ page: 1, limit: 10 });Available Client Methods
Authentication:
sendOTP({ country_code, phone_number, name })verifyOTP({ country_code, phone_number, otp })setToken(token)getToken()
Content & Pages:
fetchPages()fetchSections(pageId)fetchDemoContents(template?)
Products:
fetchProducts({ page?, limit? })
Addresses:
fetchAddresses()fetchAddress(addressId)createAddress(addressData)updateAddress(addressId, addressData)deleteAddress(addressId)
Orders:
checkoutOrder(orderData)fetchOrders()fetchOrder(orderNumber)
Examples
Complete Authentication Flow
import { useSendOTP, useVerifyOTP, useAuth } from "@lessy-js/client";
function LoginForm() {
const { sendOTP, loading: sendingOTP } = useSendOTP();
const { verifyOTP, loading: verifyingOTP } = useVerifyOTP();
const { setToken, isAuthenticated } = useAuth();
const [phone, setPhone] = useState("");
const [otp, setOtp] = useState("");
const [step, setStep] = useState("phone"); // 'phone' or 'otp'
const handleSendOTP = async (e) => {
e.preventDefault();
try {
await sendOTP({
country_code: "+1",
phone_number: phone,
name: "User",
});
setStep("otp");
} catch (err) {
alert("Failed to send OTP");
}
};
const handleVerifyOTP = async (e) => {
e.preventDefault();
try {
const result = await verifyOTP({
country_code: "+1",
phone_number: phone,
otp: otp,
});
setToken(result.token, result.customer);
} catch (err) {
alert("Invalid OTP");
}
};
if (isAuthenticated) {
return <div>You are logged in!</div>;
}
return (
<form>
{step === "phone" ? (
<>
<input
value={phone}
onChange={(e) => setPhone(e.target.value)}
placeholder="Phone number"
/>
<button onClick={handleSendOTP} disabled={sendingOTP}>
Send OTP
</button>
</>
) : (
<>
<input
value={otp}
onChange={(e) => setOtp(e.target.value)}
placeholder="Enter OTP"
/>
<button onClick={handleVerifyOTP} disabled={verifyingOTP}>
Verify OTP
</button>
</>
)}
</form>
);
}Product Listing with Pagination
import { useProducts } from "@lessy-js/client";
function ProductList() {
const [page, setPage] = useState(1);
const { products, pagination, loading, error } = useProducts({
page,
limit: 12,
});
if (loading) return <div>Loading products...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<div className="products-grid">
{products.map((product) => (
<div key={product.id}>
<h3>{product.title}</h3>
<p>{product.description}</p>
<p>
${product.price} {product.currency}
</p>
</div>
))}
</div>
{pagination && (
<div className="pagination">
<button disabled={page === 1} onClick={() => setPage(page - 1)}>
Previous
</button>
<span>
Page {pagination.page} of {pagination.totalPages}
</span>
<button
disabled={page === pagination.totalPages}
onClick={() => setPage(page + 1)}
>
Next
</button>
</div>
)}
</div>
);
}Address Management
import {
useAddresses,
useCreateAddress,
useDeleteAddress,
} from "@lessy-js/client";
function AddressManager() {
const { addresses, loading, refetch } = useAddresses();
const { createAddress, loading: creating } = useCreateAddress();
const { deleteAddress, loading: deleting } = useDeleteAddress();
const handleCreate = async () => {
try {
await createAddress({
address: "123 Main St",
city: "New York",
state: "NY",
postal_code: "10001",
country: "USA",
label: "Home",
is_default: true,
});
refetch();
} catch (err) {
alert("Failed to create address");
}
};
const handleDelete = async (id) => {
if (confirm("Delete this address?")) {
try {
await deleteAddress(id);
refetch();
} catch (err) {
alert("Failed to delete address");
}
}
};
if (loading) return <div>Loading addresses...</div>;
return (
<div>
<button onClick={handleCreate} disabled={creating}>
Add New Address
</button>
<ul>
{addresses.map((addr) => (
<li key={addr.id}>
<strong>{addr.label}</strong> - {addr.address}, {addr.city}
{addr.is_default && <span> (Default)</span>}
<button onClick={() => handleDelete(addr.id)} disabled={deleting}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}Order Checkout
import { useCheckout, useOrders } from "@lessy-js/client";
function Checkout({ cartItems, selectedAddressId }) {
const { checkout, loading } = useCheckout();
const { refetch: refetchOrders } = useOrders();
const handleCheckout = async () => {
try {
const order = await checkout({
items: cartItems.map((item) => ({
product_id: item.productId,
quantity: item.quantity,
})),
address_id: selectedAddressId,
notes: "Please deliver in the morning",
});
alert(`Order ${order.order_number} created successfully!`);
refetchOrders();
} catch (err) {
alert("Checkout failed: " + err.message);
}
};
return (
<button onClick={handleCheckout} disabled={loading}>
{loading ? "Processing..." : "Complete Order"}
</button>
);
}Error Handling
All hooks return an error object when requests fail. You should always check for errors:
const { data, loading, error } = useSomeHook();
if (error) {
return <div>Error: {error.message}</div>;
}Common error scenarios:
- 401 Unauthorized: Missing or invalid authentication token
- 404 Not Found: Resource doesn't exist
- 400 Bad Request: Invalid parameters or validation errors
- 429 Too Many Requests: Rate limit exceeded (especially for OTP endpoints)
TypeScript Support
This library is written in JavaScript but can be used with TypeScript. Type definitions may be added in future versions.
License
MIT © Bititude Technologies LLP
