move selfservice tables to medreport schema

add base medusa store frontend
This commit is contained in:
Danel Kungla
2025-07-07 13:46:22 +03:00
parent 297dd7c221
commit 2e62e4b0eb
237 changed files with 33991 additions and 189 deletions

View File

@@ -0,0 +1,96 @@
"use client"
import { convertToLocale } from "@lib/util/money"
import React from "react"
type CartTotalsProps = {
totals: {
total?: number | null
subtotal?: number | null
tax_total?: number | null
shipping_total?: number | null
discount_total?: number | null
gift_card_total?: number | null
currency_code: string
shipping_subtotal?: number | null
}
}
const CartTotals: React.FC<CartTotalsProps> = ({ totals }) => {
const {
currency_code,
total,
subtotal,
tax_total,
discount_total,
gift_card_total,
shipping_subtotal,
} = totals
return (
<div>
<div className="flex flex-col gap-y-2 txt-medium text-ui-fg-subtle ">
<div className="flex items-center justify-between">
<span className="flex gap-x-1 items-center">
Subtotal (excl. shipping and taxes)
</span>
<span data-testid="cart-subtotal" data-value={subtotal || 0}>
{convertToLocale({ amount: subtotal ?? 0, currency_code })}
</span>
</div>
{!!discount_total && (
<div className="flex items-center justify-between">
<span>Discount</span>
<span
className="text-ui-fg-interactive"
data-testid="cart-discount"
data-value={discount_total || 0}
>
-{" "}
{convertToLocale({ amount: discount_total ?? 0, currency_code })}
</span>
</div>
)}
<div className="flex items-center justify-between">
<span>Shipping</span>
<span data-testid="cart-shipping" data-value={shipping_subtotal || 0}>
{convertToLocale({ amount: shipping_subtotal ?? 0, currency_code })}
</span>
</div>
<div className="flex justify-between">
<span className="flex gap-x-1 items-center ">Taxes</span>
<span data-testid="cart-taxes" data-value={tax_total || 0}>
{convertToLocale({ amount: tax_total ?? 0, currency_code })}
</span>
</div>
{!!gift_card_total && (
<div className="flex items-center justify-between">
<span>Gift card</span>
<span
className="text-ui-fg-interactive"
data-testid="cart-gift-card-amount"
data-value={gift_card_total || 0}
>
-{" "}
{convertToLocale({ amount: gift_card_total ?? 0, currency_code })}
</span>
</div>
)}
</div>
<div className="h-px w-full border-b border-gray-200 my-4" />
<div className="flex items-center justify-between text-ui-fg-base mb-2 txt-medium ">
<span>Total</span>
<span
className="txt-xlarge-plus"
data-testid="cart-total"
data-value={total || 0}
>
{convertToLocale({ amount: total ?? 0, currency_code })}
</span>
</div>
<div className="h-px w-full border-b border-gray-200 mt-4" />
</div>
)
}
export default CartTotals

View File

@@ -0,0 +1,43 @@
import { Checkbox, Label } from "@medusajs/ui"
import React from "react"
type CheckboxProps = {
checked?: boolean
onChange?: () => void
label: string
name?: string
'data-testid'?: string
}
const CheckboxWithLabel: React.FC<CheckboxProps> = ({
checked = true,
onChange,
label,
name,
'data-testid': dataTestId
}) => {
return (
<div className="flex items-center space-x-2 ">
<Checkbox
className="text-base-regular flex items-center gap-x-2"
id="checkbox"
role="checkbox"
type="button"
checked={checked}
aria-checked={checked}
onClick={onChange}
name={name}
data-testid={dataTestId}
/>
<Label
htmlFor="checkbox"
className="!transform-none !txt-medium"
size="large"
>
{label}
</Label>
</div>
)
}
export default CheckboxWithLabel

View File

@@ -0,0 +1,42 @@
import { deleteLineItem } from "@lib/data/cart"
import { Spinner, Trash } from "@medusajs/icons"
import { clx } from "@medusajs/ui"
import { useState } from "react"
const DeleteButton = ({
id,
children,
className,
}: {
id: string
children?: React.ReactNode
className?: string
}) => {
const [isDeleting, setIsDeleting] = useState(false)
const handleDelete = async (id: string) => {
setIsDeleting(true)
await deleteLineItem(id).catch((err) => {
setIsDeleting(false)
})
}
return (
<div
className={clx(
"flex items-center justify-between text-small-regular",
className
)}
>
<button
className="flex gap-x-1 text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer"
onClick={() => handleDelete(id)}
>
{isDeleting ? <Spinner className="animate-spin" /> : <Trash />}
<span>{children}</span>
</button>
</div>
)
}
export default DeleteButton

View File

@@ -0,0 +1,9 @@
import { clx } from "@medusajs/ui"
const Divider = ({ className }: { className?: string }) => (
<div
className={clx("h-px w-full border-b border-gray-200 mt-1", className)}
/>
)
export default Divider

View File

@@ -0,0 +1,60 @@
import { EllipseMiniSolid } from "@medusajs/icons"
import { Label, RadioGroup, Text, clx } from "@medusajs/ui"
type FilterRadioGroupProps = {
title: string
items: {
value: string
label: string
}[]
value: any
handleChange: (...args: any[]) => void
"data-testid"?: string
}
const FilterRadioGroup = ({
title,
items,
value,
handleChange,
"data-testid": dataTestId,
}: FilterRadioGroupProps) => {
return (
<div className="flex gap-x-3 flex-col gap-y-3">
<Text className="txt-compact-small-plus text-ui-fg-muted">{title}</Text>
<RadioGroup data-testid={dataTestId} onValueChange={handleChange}>
{items?.map((i) => (
<div
key={i.value}
className={clx("flex gap-x-2 items-center", {
"ml-[-23px]": i.value === value,
})}
>
{i.value === value && <EllipseMiniSolid />}
<RadioGroup.Item
checked={i.value === value}
className="hidden peer"
id={i.value}
value={i.value}
/>
<Label
htmlFor={i.value}
className={clx(
"!txt-compact-small !transform-none text-ui-fg-subtle hover:cursor-pointer",
{
"text-ui-fg-base": i.value === value,
}
)}
data-testid="radio-label"
data-active={i.value === value}
>
{i.label}
</Label>
</div>
))}
</RadioGroup>
</div>
)
}
export default FilterRadioGroup

View File

@@ -0,0 +1,55 @@
// cart-totals
export { default as CartTotals } from "./cart-totals";
export * from "./cart-totals";
// checkbox
export { default as Checkbox } from "./checkbox";
export * from "./checkbox";
// delete-button
export { default as DeleteButton } from "./delete-button";
export * from "./delete-button";
// divider
export { default as Divider } from "./divider";
export * from "./divider";
// filter-radio-group
export { default as FilterRadioGroup } from "./filter-radio-group";
export * from "./filter-radio-group";
// input
export { default as Input } from "./input";
export * from "./input";
// interactive-link
export { default as InteractiveLink } from "./interactive-link";
export * from "./interactive-link";
// line-item-options
export { default as LineItemOptions } from "./line-item-options";
export * from "./line-item-options";
// line-item-price
export { default as LineItemPrice } from "./line-item-price";
export * from "./line-item-price";
// line-item-unit-price
export { default as LineItemUnitPrice } from "./line-item-unit-price";
export * from "./line-item-unit-price";
// localized-client-link
export { default as LocalizedClientLink } from "./localized-client-link";
export * from "./localized-client-link";
// modal
export { default as Modal } from "./modal";
export * from "./modal";
// native-select
export { default as NativeSelect } from "./native-select";
export * from "./native-select";
// radio
export { default as Radio } from "./radio";
export * from "./radio";

View File

@@ -0,0 +1,76 @@
import { Label } from "@medusajs/ui"
import React, { useEffect, useImperativeHandle, useState } from "react"
import Eye from "@modules/common/icons/eye"
import EyeOff from "@modules/common/icons/eye-off"
type InputProps = Omit<
Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">,
"placeholder"
> & {
label: string
errors?: Record<string, unknown>
touched?: Record<string, unknown>
name: string
topLabel?: string
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ type, name, label, touched, required, topLabel, ...props }, ref) => {
const inputRef = React.useRef<HTMLInputElement>(null)
const [showPassword, setShowPassword] = useState(false)
const [inputType, setInputType] = useState(type)
useEffect(() => {
if (type === "password" && showPassword) {
setInputType("text")
}
if (type === "password" && !showPassword) {
setInputType("password")
}
}, [type, showPassword])
useImperativeHandle(ref, () => inputRef.current!)
return (
<div className="flex flex-col w-full">
{topLabel && (
<Label className="mb-2 txt-compact-medium-plus">{topLabel}</Label>
)}
<div className="flex relative z-0 w-full txt-compact-medium">
<input
type={inputType}
name={name}
placeholder=" "
required={required}
className="pt-4 pb-1 block w-full h-11 px-4 mt-0 bg-ui-bg-field border rounded-md appearance-none focus:outline-none focus:ring-0 focus:shadow-borders-interactive-with-active border-ui-border-base hover:bg-ui-bg-field-hover"
{...props}
ref={inputRef}
/>
<label
htmlFor={name}
onClick={() => inputRef.current?.focus()}
className="flex items-center justify-center mx-3 px-1 transition-all absolute duration-300 top-3 -z-1 origin-0 text-ui-fg-subtle"
>
{label}
{required && <span className="text-rose-500">*</span>}
</label>
{type === "password" && (
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="text-ui-fg-subtle px-4 focus:outline-none transition-all duration-150 outline-none focus:text-ui-fg-base absolute right-0 top-3"
>
{showPassword ? <Eye /> : <EyeOff />}
</button>
)}
</div>
</div>
)
}
)
Input.displayName = "Input"
export default Input

View File

@@ -0,0 +1,33 @@
import { ArrowUpRightMini } from "@medusajs/icons"
import { Text } from "@medusajs/ui"
import LocalizedClientLink from "../localized-client-link"
type InteractiveLinkProps = {
href: string
children?: React.ReactNode
onClick?: () => void
}
const InteractiveLink = ({
href,
children,
onClick,
...props
}: InteractiveLinkProps) => {
return (
<LocalizedClientLink
className="flex gap-x-1 items-center group"
href={href}
onClick={onClick}
{...props}
>
<Text className="text-ui-fg-interactive">{children}</Text>
<ArrowUpRightMini
className="group-hover:rotate-45 ease-in-out duration-150"
color="var(--fg-interactive)"
/>
</LocalizedClientLink>
)
}
export default InteractiveLink

View File

@@ -0,0 +1,26 @@
import { HttpTypes } from "@medusajs/types"
import { Text } from "@medusajs/ui"
type LineItemOptionsProps = {
variant: HttpTypes.StoreProductVariant | undefined
"data-testid"?: string
"data-value"?: HttpTypes.StoreProductVariant
}
const LineItemOptions = ({
variant,
"data-testid": dataTestid,
"data-value": dataValue,
}: LineItemOptionsProps) => {
return (
<Text
data-testid={dataTestid}
data-value={dataValue}
className="inline-block txt-medium text-ui-fg-subtle w-full overflow-hidden text-ellipsis"
>
Variant: {variant?.title}
</Text>
)
}
export default LineItemOptions

View File

@@ -0,0 +1,64 @@
import { getPercentageDiff } from "@lib/util/get-precentage-diff"
import { convertToLocale } from "@lib/util/money"
import { HttpTypes } from "@medusajs/types"
import { clx } from "@medusajs/ui"
type LineItemPriceProps = {
item: HttpTypes.StoreCartLineItem | HttpTypes.StoreOrderLineItem
style?: "default" | "tight"
currencyCode: string
}
const LineItemPrice = ({
item,
style = "default",
currencyCode,
}: LineItemPriceProps) => {
const { total, original_total } = item
const originalPrice = original_total
const currentPrice = total
const hasReducedPrice = currentPrice < originalPrice
return (
<div className="flex flex-col gap-x-2 text-ui-fg-subtle items-end">
<div className="text-left">
{hasReducedPrice && (
<>
<p>
{style === "default" && (
<span className="text-ui-fg-subtle">Original: </span>
)}
<span
className="line-through text-ui-fg-muted"
data-testid="product-original-price"
>
{convertToLocale({
amount: originalPrice,
currency_code: currencyCode,
})}
</span>
</p>
{style === "default" && (
<span className="text-ui-fg-interactive">
-{getPercentageDiff(originalPrice, currentPrice || 0)}%
</span>
)}
</>
)}
<span
className={clx("text-base-regular", {
"text-ui-fg-interactive": hasReducedPrice,
})}
data-testid="product-price"
>
{convertToLocale({
amount: currentPrice,
currency_code: currencyCode,
})}
</span>
</div>
</div>
)
}
export default LineItemPrice

View File

@@ -0,0 +1,61 @@
import { convertToLocale } from "@lib/util/money"
import { HttpTypes } from "@medusajs/types"
import { clx } from "@medusajs/ui"
type LineItemUnitPriceProps = {
item: HttpTypes.StoreCartLineItem | HttpTypes.StoreOrderLineItem
style?: "default" | "tight"
currencyCode: string
}
const LineItemUnitPrice = ({
item,
style = "default",
currencyCode,
}: LineItemUnitPriceProps) => {
const { total, original_total } = item
const hasReducedPrice = total < original_total
const percentage_diff = Math.round(
((original_total - total) / original_total) * 100
)
return (
<div className="flex flex-col text-ui-fg-muted justify-center h-full">
{hasReducedPrice && (
<>
<p>
{style === "default" && (
<span className="text-ui-fg-muted">Original: </span>
)}
<span
className="line-through"
data-testid="product-unit-original-price"
>
{convertToLocale({
amount: original_total / item.quantity,
currency_code: currencyCode,
})}
</span>
</p>
{style === "default" && (
<span className="text-ui-fg-interactive">-{percentage_diff}%</span>
)}
</>
)}
<span
className={clx("text-base-regular", {
"text-ui-fg-interactive": hasReducedPrice,
})}
data-testid="product-unit-price"
>
{convertToLocale({
amount: total / item.quantity,
currency_code: currencyCode,
})}
</span>
</div>
)
}
export default LineItemUnitPrice

View File

@@ -0,0 +1,32 @@
"use client"
import Link from "next/link"
import { useParams } from "next/navigation"
import React from "react"
/**
* Use this component to create a Next.js `<Link />` that persists the current country code in the url,
* without having to explicitly pass it as a prop.
*/
const LocalizedClientLink = ({
children,
href,
...props
}: {
children?: React.ReactNode
href: string
className?: string
onClick?: () => void
passHref?: true
[x: string]: any
}) => {
const { countryCode } = useParams()
return (
<Link href={`/${countryCode}${href}`} {...props}>
{children}
</Link>
)
}
export default LocalizedClientLink

View File

@@ -0,0 +1,118 @@
import { Dialog, Transition } from "@headlessui/react"
import { clx } from "@medusajs/ui"
import React, { Fragment } from "react"
import { ModalProvider, useModal } from "@lib/context/modal-context"
import X from "@modules/common/icons/x"
type ModalProps = {
isOpen: boolean
close: () => void
size?: "small" | "medium" | "large"
search?: boolean
children: React.ReactNode
'data-testid'?: string
}
const Modal = ({
isOpen,
close,
size = "medium",
search = false,
children,
'data-testid': dataTestId
}: ModalProps) => {
return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-[75]" onClose={close}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-opacity-75 backdrop-blur-md h-screen" />
</Transition.Child>
<div className="fixed inset-0 overflow-y-hidden">
<div
className={clx(
"flex min-h-full h-full justify-center p-4 text-center",
{
"items-center": !search,
"items-start": search,
}
)}
>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel
data-testid={dataTestId}
className={clx(
"flex flex-col justify-start w-full transform p-5 text-left align-middle transition-all max-h-[75vh] h-fit",
{
"max-w-md": size === "small",
"max-w-xl": size === "medium",
"max-w-3xl": size === "large",
"bg-transparent shadow-none": search,
"bg-white shadow-xl border rounded-rounded": !search,
}
)}
>
<ModalProvider close={close}>{children}</ModalProvider>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
)
}
const Title: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { close } = useModal()
return (
<Dialog.Title className="flex items-center justify-between">
<div className="text-large-semi">{children}</div>
<div>
<button onClick={close} data-testid="close-modal-button">
<X size={20} />
</button>
</div>
</Dialog.Title>
)
}
const Description: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return (
<Dialog.Description className="flex text-small-regular text-ui-fg-base items-center justify-center pt-2 pb-4 h-full">
{children}
</Dialog.Description>
)
}
const Body: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return <div className="flex justify-center">{children}</div>
}
const Footer: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return <div className="flex items-center justify-end gap-x-4">{children}</div>
}
Modal.Title = Title
Modal.Description = Description
Modal.Body = Body
Modal.Footer = Footer
export default Modal

View File

@@ -0,0 +1,74 @@
import { ChevronUpDown } from "@medusajs/icons"
import { clx } from "@medusajs/ui"
import {
SelectHTMLAttributes,
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react"
export type NativeSelectProps = {
placeholder?: string
errors?: Record<string, unknown>
touched?: Record<string, unknown>
} & SelectHTMLAttributes<HTMLSelectElement>
const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
(
{ placeholder = "Select...", defaultValue, className, children, ...props },
ref
) => {
const innerRef = useRef<HTMLSelectElement>(null)
const [isPlaceholder, setIsPlaceholder] = useState(false)
useImperativeHandle<HTMLSelectElement | null, HTMLSelectElement | null>(
ref,
() => innerRef.current
)
useEffect(() => {
if (innerRef.current && innerRef.current.value === "") {
setIsPlaceholder(true)
} else {
setIsPlaceholder(false)
}
}, [innerRef.current?.value])
return (
<div>
<div
onFocus={() => innerRef.current?.focus()}
onBlur={() => innerRef.current?.blur()}
className={clx(
"relative flex items-center text-base-regular border border-ui-border-base bg-ui-bg-subtle rounded-md hover:bg-ui-bg-field-hover",
className,
{
"text-ui-fg-muted": isPlaceholder,
}
)}
>
<select
ref={innerRef}
defaultValue={defaultValue}
{...props}
className="appearance-none flex-1 bg-transparent border-none px-4 py-2.5 transition-colors duration-150 outline-none "
>
<option disabled value="">
{placeholder}
</option>
{children}
</select>
<span className="absolute right-4 inset-y-0 flex items-center pointer-events-none ">
<ChevronUpDown />
</span>
</div>
</div>
)
}
)
NativeSelect.displayName = "NativeSelect"
export default NativeSelect

View File

@@ -0,0 +1,27 @@
const Radio = ({ checked, 'data-testid': dataTestId }: { checked: boolean, 'data-testid'?: string }) => {
return (
<>
<button
type="button"
role="radio"
aria-checked="true"
data-state={checked ? "checked" : "unchecked"}
className="group relative flex h-5 w-5 items-center justify-center outline-none"
data-testid={dataTestId || 'radio-button'}
>
<div className="shadow-borders-base group-hover:shadow-borders-strong-with-shadow bg-ui-bg-base group-data-[state=checked]:bg-ui-bg-interactive group-data-[state=checked]:shadow-borders-interactive group-focus:!shadow-borders-interactive-with-focus group-disabled:!bg-ui-bg-disabled group-disabled:!shadow-borders-base flex h-[14px] w-[14px] items-center justify-center rounded-full transition-all">
{checked && (
<span
data-state={checked ? "checked" : "unchecked"}
className="group flex items-center justify-center"
>
<div className="bg-ui-bg-base shadow-details-contrast-on-bg-interactive group-disabled:bg-ui-fg-disabled rounded-full group-disabled:shadow-none h-1.5 w-1.5"></div>
</span>
)}
</div>
</button>
</>
)
}
export default Radio

View File

@@ -0,0 +1,37 @@
import React from "react"
import { IconProps } from "types/icon"
const Back: React.FC<IconProps> = ({
size = "16",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M4 3.5V9.5H10"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.09714 14.014C4.28641 15.7971 4.97372 16.7931 6.22746 18.0783C7.4812 19.3635 9.13155 20.1915 10.9137 20.4293C12.6958 20.6671 14.5064 20.301 16.0549 19.3898C17.6033 18.4785 18.8 17.0749 19.4527 15.4042C20.1054 13.7335 20.1764 11.8926 19.6543 10.1769C19.1322 8.46112 18.0472 6.97003 16.5735 5.94286C15.0997 4.91569 13.3227 4.412 11.5275 4.51261C9.73236 4.61323 8.02312 5.31232 6.6741 6.4977L4 8.89769"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default Back

View File

@@ -0,0 +1,26 @@
import React from "react"
import { IconProps } from "types/icon"
const Ideal: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
role="img"
xmlns="http://www.w3.org/2000/svg"
fill={color}
{...attributes}
>
<title>Bancontact icon</title>
<path d="M21.385 9.768h-7.074l-4.293 5.022H1.557L3.84 12.1H1.122C.505 12.1 0 12.616 0 13.25v2.428c0 .633.505 1.15 1.122 1.15h12.933c.617 0 1.46-.384 1.874-.854l1.956-2.225 3.469-3.946.031-.035zm-1.123 1.279l-.751.855.75-.855zm2.616-3.875H9.982c-.617 0-1.462.384-1.876.853l-5.49 6.208h7.047l4.368-5.02h8.424l-2.263 2.689h2.686c.617 0 1.122-.518 1.122-1.151V8.323c0-.633-.505-1.15-1.122-1.15zm-1.87 3.024l-.374.427-.1.114.474-.54z" />
</svg>
)
}
export default Ideal

View File

@@ -0,0 +1,29 @@
import React from "react";
import { IconProps } from "../../../types/icon";
const ChevronDown: React.FC<IconProps> = ({
size = "16",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M4 6L8 10L12 6"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
};
export default ChevronDown;

View File

@@ -0,0 +1,37 @@
import React from "react"
import { IconProps } from "types/icon"
const EyeOff: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M8.56818 4.70906C9.0375 4.59921 9.518 4.54429 10 4.54543C14.7727 4.54543 17.5 9.99997 17.5 9.99997C17.0861 10.7742 16.5925 11.5032 16.0273 12.175M11.4455 11.4454C11.2582 11.6464 11.0324 11.8076 10.7815 11.9194C10.5306 12.0312 10.2597 12.0913 9.98506 12.0961C9.71042 12.101 9.43761 12.0505 9.18292 11.9476C8.92822 11.8447 8.69686 11.6916 8.50262 11.4973C8.30839 11.3031 8.15527 11.0718 8.05239 10.8171C7.94952 10.5624 7.899 10.2896 7.90384 10.0149C7.90869 9.74027 7.9688 9.46941 8.0806 9.2185C8.19239 8.9676 8.35358 8.74178 8.55455 8.55452M14.05 14.05C12.8845 14.9384 11.4653 15.4306 10 15.4545C5.22727 15.4545 2.5 9.99997 2.5 9.99997C3.34811 8.41945 4.52441 7.03857 5.95 5.94997L14.05 14.05Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M2.5 2.5L17.5 17.5"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default EyeOff

View File

@@ -0,0 +1,37 @@
import React from "react"
import { IconProps } from "types/icon"
const Eye: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M2.5 9.99992C2.5 9.99992 5.22727 4.58325 10 4.58325C14.7727 4.58325 17.5 9.99992 17.5 9.99992C17.5 9.99992 14.7727 15.4166 10 15.4166C5.22727 15.4166 2.5 9.99992 2.5 9.99992Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.99965 12.074C11.145 12.074 12.0735 11.1455 12.0735 10.0001C12.0735 8.85477 11.145 7.92627 9.99965 7.92627C8.85428 7.92627 7.92578 8.85477 7.92578 10.0001C7.92578 11.1455 8.85428 12.074 9.99965 12.074Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default Eye

View File

@@ -0,0 +1,65 @@
import React from "react"
import { IconProps } from "types/icon"
const FastDelivery: React.FC<IconProps> = ({
size = "16",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M3.63462 7.35205H2.70508"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.56416 4.56348H2.70508"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M16.6483 19.4365H3.63477"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M16.9034 4.56348L15.9868 7.61888C15.8688 8.01207 15.5063 8.28164 15.0963 8.28164H12.2036C11.5808 8.28164 11.1346 7.68115 11.3131 7.08532L12.0697 4.56348"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8.28125 12.9297H10.2612"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17.055 15.718H7.21305C5.71835 15.718 4.64659 14.2772 5.07603 12.8457L7.08384 6.15299C7.36735 5.20951 8.23554 4.56348 9.22086 4.56348H19.0638C20.5585 4.56348 21.6302 6.00426 21.2008 7.43576L19.193 14.1284C18.9095 15.0719 18.0403 15.718 17.055 15.718Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default FastDelivery

View File

@@ -0,0 +1,26 @@
import React from "react"
import { IconProps } from "types/icon"
const Ideal: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width="20px"
height="20px"
viewBox="0 0 24 24"
role="img"
xmlns="http://www.w3.org/2000/svg"
fill={color}
{...attributes}
>
<title>iDEAL icon</title>
<path d="M.975 2.61v18.782h11.411c6.89 0 10.64-3.21 10.64-9.415 0-6.377-4.064-9.367-10.64-9.367H.975zm11.411-.975C22.491 1.635 24 8.115 24 11.977c0 6.7-4.124 10.39-11.614 10.39H0V1.635h12.386z M2.506 13.357h3.653v6.503H2.506z M6.602 10.082a2.27 2.27 0 1 1-4.54 0 2.27 2.27 0 0 1 4.54 0m1.396-1.057v2.12h.65c.45 0 .867-.13.867-1.077 0-.924-.463-1.043-.867-1.043h-.65zm10.85-1.054h1.053v3.174h1.56c-.428-5.758-4.958-7.002-9.074-7.002H7.999v3.83h.65c1.183 0 1.92.803 1.92 2.095 0 1.333-.719 2.129-1.92 2.129h-.65v7.665h4.388c6.692 0 9.021-3.107 9.103-7.665h-2.64V7.97zm-2.93 2.358h.76l-.348-1.195h-.063l-.35 1.195zm-1.643 1.87l1.274-4.228h1.497l1.274 4.227h-1.095l-.239-.818H15.61l-.24.818h-1.095zm-.505-1.054v1.052h-2.603V7.973h2.519v1.052h-1.467v.49h1.387v1.05H12.22v.58h1.55z" />
</svg>
)
}
export default Ideal

View File

@@ -0,0 +1,71 @@
// back
export { default as BackIcon } from "./back";
export * from "./back";
// bancontact
export { default as BancontactIcon } from "./bancontact";
export * from "./bancontact";
// chevron-down
export { default as ChevronDownIcon } from "./chevron-down";
export * from "./chevron-down";
// eye-off
export { default as EyeOffIcon } from "./eye-off";
export * from "./eye-off";
// eye
export { default as EyeIcon } from "./eye";
export * from "./eye";
// fast-delivery
export { default as FastDeliveryIcon } from "./fast-delivery";
export * from "./fast-delivery";
// ideal
export { default as IdealIcon } from "./ideal";
export * from "./ideal";
// map-pin
export { default as MapPinIcon } from "./map-pin";
export * from "./map-pin";
// medusa
export { default as MedusaIcon } from "./medusa";
export * from "./medusa";
// nextjs
export { default as NextjsIcon } from "./nextjs";
export * from "./nextjs";
// package
export { default as PackageIcon } from "./package";
export * from "./package";
// paypal
export { default as PaypalIcon } from "./paypal";
export * from "./paypal";
// placeholder-image
export { default as PlaceholderImageIcon } from "./placeholder-image";
export * from "./placeholder-image";
// refresh
export { default as RefreshIcon } from "./refresh";
export * from "./refresh";
// spinner
export { default as SpinnerIcon } from "./spinner";
export * from "./spinner";
// trash
export { default as TrashIcon } from "./trash";
export * from "./trash";
// user
export { default as UserIcon } from "./user";
export * from "./user";
// x
export { default as XIcon } from "./x";
export * from "./x";

View File

@@ -0,0 +1,37 @@
import React from "react"
import { IconProps } from "types/icon"
const MapPin: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M15.8337 8.63636C15.8337 13.4091 10.0003 17.5 10.0003 17.5C10.0003 17.5 4.16699 13.4091 4.16699 8.63636C4.16699 7.0089 4.78157 5.44809 5.87554 4.2973C6.9695 3.14651 8.45323 2.5 10.0003 2.5C11.5474 2.5 13.0312 3.14651 14.1251 4.2973C15.2191 5.44809 15.8337 7.0089 15.8337 8.63636Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.99967 9.99996C10.9201 9.99996 11.6663 9.25377 11.6663 8.33329C11.6663 7.41282 10.9201 6.66663 9.99967 6.66663C9.0792 6.66663 8.33301 7.41282 8.33301 8.33329C8.33301 9.25377 9.0792 9.99996 9.99967 9.99996Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default MapPin

View File

@@ -0,0 +1,27 @@
import React from "react"
import { IconProps } from "types/icon"
const Medusa: React.FC<IconProps> = ({
size = "20",
color = "#9CA3AF",
...attributes
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
{...attributes}
>
<path
d="M15.2447 2.92183L11.1688 0.576863C9.83524 -0.192288 8.20112 -0.192288 6.86753 0.576863L2.77285 2.92183C1.45804 3.69098 0.631592 5.11673 0.631592 6.63627V11.345C0.631592 12.8833 1.45804 14.2903 2.77285 15.0594L6.84875 17.4231C8.18234 18.1923 9.81646 18.1923 11.15 17.4231L15.2259 15.0594C16.5595 14.2903 17.3672 12.8833 17.3672 11.345V6.63627C17.4048 5.11673 16.5783 3.69098 15.2447 2.92183ZM9.00879 13.1834C6.69849 13.1834 4.82019 11.3075 4.82019 9C4.82019 6.69255 6.69849 4.81657 9.00879 4.81657C11.3191 4.81657 13.2162 6.69255 13.2162 9C13.2162 11.3075 11.3379 13.1834 9.00879 13.1834Z"
fill={color}
/>
</svg>
)
}
export default Medusa

View File

@@ -0,0 +1,27 @@
import React from "react"
import { IconProps } from "types/icon"
const NextJs: React.FC<IconProps> = ({
size = "20",
color = "#9CA3AF",
...attributes
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
{...attributes}
>
<path
d="M8.41117 0.0131402C8.3725 0.0166554 8.24946 0.0289589 8.13873 0.0377471C5.58488 0.267998 3.19273 1.64599 1.67764 3.76395C0.833977 4.94157 0.294381 6.27737 0.090495 7.69227C0.0184318 8.18617 0.00964355 8.33206 0.00964355 9.00172C0.00964355 9.67138 0.0184318 9.81726 0.090495 10.3112C0.579119 13.6876 2.98181 16.5244 6.24048 17.5755C6.82402 17.7636 7.43919 17.8919 8.13873 17.9692C8.41117 17.9991 9.58879 17.9991 9.86122 17.9692C11.0687 17.8356 12.0917 17.5368 13.1006 17.0218C13.2552 16.9427 13.2851 16.9216 13.264 16.9041C13.25 16.8935 12.5908 16.0094 11.7999 14.9408L10.3621 12.9986L8.56057 10.3323C7.56926 8.86638 6.75371 7.66767 6.74668 7.66767C6.73965 7.66591 6.73262 8.85056 6.7291 10.2971C6.72383 12.8299 6.72207 12.9318 6.69044 12.9916C6.64474 13.0777 6.60958 13.1128 6.53576 13.1515C6.47952 13.1796 6.43031 13.1849 6.1649 13.1849H5.86083L5.77998 13.1339C5.72725 13.1005 5.68858 13.0566 5.66222 13.0056L5.62531 12.9265L5.62882 9.40246L5.63409 5.87663L5.68858 5.80808C5.7167 5.77117 5.77646 5.72372 5.81865 5.70087C5.89071 5.66571 5.91883 5.6622 6.2229 5.6622C6.58146 5.6622 6.64122 5.67626 6.73438 5.7782C6.76074 5.80632 7.73623 7.27571 8.90331 9.04566C10.0704 10.8156 11.6663 13.2324 12.4502 14.4188L13.8739 16.5754L13.946 16.5279C14.584 16.1131 15.2589 15.5226 15.7933 14.9074C16.9305 13.6015 17.6634 12.009 17.9095 10.3112C17.9815 9.81726 17.9903 9.67138 17.9903 9.00172C17.9903 8.33206 17.9815 8.18617 17.9095 7.69227C17.4208 4.31585 15.0181 1.47901 11.7595 0.427943C11.1847 0.241633 10.5731 0.113326 9.88758 0.0359895C9.71885 0.0184131 8.55705 -0.000920974 8.41117 0.0131402ZM12.0917 5.45128C12.176 5.49346 12.2446 5.57432 12.2692 5.65868C12.2832 5.70438 12.2868 6.68163 12.2832 8.88395L12.278 12.0442L11.7208 11.19L11.1619 10.3358V8.03853C11.1619 6.55332 11.1689 5.71844 11.1795 5.67802C11.2076 5.57959 11.2691 5.50225 11.3535 5.45655C11.4255 5.41964 11.4519 5.41613 11.7278 5.41613C11.988 5.41613 12.0337 5.41964 12.0917 5.45128Z"
fill={color}
/>
</svg>
)
}
export default NextJs

View File

@@ -0,0 +1,44 @@
import React from "react"
import { IconProps } from "types/icon"
const Package: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M13.3634 8.02695L6.73047 4.21271"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M16.724 12.9577V6.98101C16.7237 6.71899 16.6546 6.46164 16.5234 6.23479C16.3923 6.00794 16.2038 5.81956 15.9769 5.68855L10.7473 2.70018C10.5201 2.56904 10.2625 2.5 10.0002 2.5C9.7379 2.5 9.48024 2.56904 9.25309 2.70018L4.02346 5.68855C3.79654 5.81956 3.60806 6.00794 3.47693 6.23479C3.3458 6.46164 3.27664 6.71899 3.27637 6.98101V12.9577C3.27664 13.2198 3.3458 13.4771 3.47693 13.704C3.60806 13.9308 3.79654 14.1192 4.02346 14.2502L9.25309 17.2386C9.48024 17.3697 9.7379 17.4388 10.0002 17.4388C10.2625 17.4388 10.5201 17.3697 10.7473 17.2386L15.9769 14.2502C16.2038 14.1192 16.3923 13.9308 16.5234 13.704C16.6546 13.4771 16.7237 13.2198 16.724 12.9577Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3.47852 6.20404L10.0006 9.97685L16.5227 6.20404"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default Package

View File

@@ -0,0 +1,30 @@
const PayPal = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
height="20"
width="20"
viewBox="0 0 26 25"
id="paypalIcon"
>
<path
fill="none"
stroke="#303c42"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
d="M6.9 20.5H2c-.6 0-.5-.1-.5-.5s2.9-18 3-18.5.5-1 1-1h10c2.8 0 5 2.2 5 5h0c0 4.4-3.6 8-8 8H7.9"
></path>
<path
fill="none"
stroke="#303c42"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
d="M7 23.5c-.3 0-.5-.2-.5-.5 0 0 0 0 0 0 0-.3 2.4-16 2.5-16.5s.3-1 1-1h7.5c2.8 0 5 2.2 5 5h0c0 3.9-3.1 7-7 7h-2l-1 6H7z"
></path>
</svg>
)
}
export default PayPal

View File

@@ -0,0 +1,44 @@
import React from "react"
import { IconProps } from "types/icon"
const PlaceholderImage: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M15.3141 3.16699H4.68453C3.84588 3.16699 3.16602 3.84685 3.16602 4.6855V15.3151C3.16602 16.1537 3.84588 16.8336 4.68453 16.8336H15.3141C16.1527 16.8336 16.8326 16.1537 16.8326 15.3151V4.6855C16.8326 3.84685 16.1527 3.16699 15.3141 3.16699Z"
stroke={color}
strokeWidth="1.53749"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7.91699 9.16699C8.60735 9.16699 9.16699 8.60735 9.16699 7.91699C9.16699 7.22664 8.60735 6.66699 7.91699 6.66699C7.22664 6.66699 6.66699 7.22664 6.66699 7.91699C6.66699 8.60735 7.22664 9.16699 7.91699 9.16699Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M16.6667 12.5756L13.0208 9.1665L5 16.6665"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default PlaceholderImage

View File

@@ -0,0 +1,51 @@
import React from "react"
import { IconProps } from "types/icon"
const Refresh: React.FC<IconProps> = ({
size = "16",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M19.8007 3.33301V8.53308H14.6006"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.2002 12C4.20157 10.4949 4.63839 9.02228 5.45797 7.75984C6.27755 6.4974 7.44488 5.49905 8.81917 4.8852C10.1935 4.27135 11.716 4.06823 13.2031 4.30034C14.6903 4.53244 16.0785 5.18986 17.2004 6.19329L19.8004 8.53332"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.2002 20.6669V15.4668H9.40027"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M19.8004 12C19.799 13.5051 19.3622 14.9778 18.5426 16.2402C17.7231 17.5026 16.5557 18.501 15.1814 19.1148C13.8072 19.7287 12.2846 19.9318 10.7975 19.6997C9.31033 19.4676 7.9221 18.8102 6.80023 17.8067L4.2002 15.4667"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default Refresh

View File

@@ -0,0 +1,37 @@
import React from "react"
import { IconProps } from "types/icon"
const Spinner: React.FC<IconProps> = ({
size = "16",
color = "currentColor",
...attributes
}) => {
return (
<svg
className="animate-spin"
width={size}
height={size}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
{...attributes}
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke={color}
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill={color}
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
)
}
export default Spinner

View File

@@ -0,0 +1,51 @@
import React from "react"
import { IconProps } from "types/icon"
const Trash: React.FC<IconProps> = ({
size = "16",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M3.33301 5.49054H4.81449H16.6663"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7.14286 5.5V4C7.14286 3.60218 7.29337 3.22064 7.56128 2.93934C7.82919 2.65804 8.19255 2.5 8.57143 2.5H11.4286C11.8075 2.5 12.1708 2.65804 12.4387 2.93934C12.7066 3.22064 12.8571 3.60218 12.8571 4V5.5M15 5.5V16C15 16.3978 14.8495 16.7794 14.5816 17.0607C14.3137 17.342 13.9503 17.5 13.5714 17.5H6.42857C6.04969 17.5 5.68633 17.342 5.41842 17.0607C5.15051 16.7794 5 16.3978 5 16V5.5H15Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M8.33203 9.23724V13.4039"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11.666 9.23724V13.4039"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default Trash

View File

@@ -0,0 +1,37 @@
import React from "react"
import { IconProps } from "types/icon"
const User: React.FC<IconProps> = ({
size = "16",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M16.6663 18V16.3333C16.6663 15.4493 16.3152 14.6014 15.69 13.9763C15.0649 13.3512 14.2171 13 13.333 13H6.66634C5.78229 13 4.93444 13.3512 4.30932 13.9763C3.6842 14.6014 3.33301 15.4493 3.33301 16.3333V18"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M10.0003 9.66667C11.8413 9.66667 13.3337 8.17428 13.3337 6.33333C13.3337 4.49238 11.8413 3 10.0003 3C8.15938 3 6.66699 4.49238 6.66699 6.33333C6.66699 8.17428 8.15938 9.66667 10.0003 9.66667Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default User

View File

@@ -0,0 +1,37 @@
import React from "react"
import { IconProps } from "types/icon"
const X: React.FC<IconProps> = ({
size = "20",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M15 5L5 15"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5 5L15 15"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default X