ThreadCount Community edition
Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/* Structured data.
|
||||
*
|
||||
* Search engines can read the pages perfectly well; what they can't do is work out that
|
||||
* ThreadCount is one free product, made by one identifiable outfit, for one narrow job. That is
|
||||
* what this states — and it is stated only where it is true, because marking up claims a page
|
||||
* doesn't make is the fastest way to lose the rich result entirely.
|
||||
*
|
||||
* Notably absent: aggregateRating and review. There are no ratings, and inventing them is both a
|
||||
* policy violation and a lie. */
|
||||
|
||||
const SITE = process.env.NEXT_PUBLIC_SITE_URL || "https://threadcount.tech";
|
||||
import { PRICES } from "./plan";
|
||||
|
||||
export const organization = {
|
||||
"@type": "Organization",
|
||||
"@id": `${SITE}/#organization`,
|
||||
name: "ThreadCount",
|
||||
url: SITE,
|
||||
logo: `${SITE}/og.png`,
|
||||
email: "hello@threadcount.tech",
|
||||
description: "Uniform stock management for healthcare: hospitals, aged care, clinics and community care.",
|
||||
areaServed: { "@type": "Country", name: "Australia" },
|
||||
contactPoint: [{
|
||||
"@type": "ContactPoint",
|
||||
contactType: "customer support",
|
||||
email: "hello@threadcount.tech",
|
||||
availableLanguage: ["English"],
|
||||
}],
|
||||
};
|
||||
|
||||
export const website = {
|
||||
"@type": "WebSite",
|
||||
"@id": `${SITE}/#website`,
|
||||
url: SITE,
|
||||
name: "ThreadCount",
|
||||
publisher: { "@id": `${SITE}/#organization` },
|
||||
inLanguage: "en-AU",
|
||||
};
|
||||
|
||||
/* The product itself, with its price as it stands. While plans are off the one offer is `price:
|
||||
"0"` — the honest and useful part, since a free-tier signal is exactly what someone comparing
|
||||
options is filtering on. Once plans are live the offers are the three editions from the pricing
|
||||
page, the free one first, read from lib/plan.ts so the markup cannot drift from the page. */
|
||||
export const softwareApplication = (live: boolean) => ({
|
||||
"@type": "SoftwareApplication",
|
||||
"@id": `${SITE}/#software`,
|
||||
name: "ThreadCount",
|
||||
applicationCategory: "BusinessApplication",
|
||||
applicationSubCategory: "Inventory management",
|
||||
operatingSystem: "Web, Android",
|
||||
url: SITE,
|
||||
publisher: { "@id": `${SITE}/#organization` },
|
||||
description:
|
||||
"Uniform stock management for hospitals, aged-care homes, clinics and community care: what is on the shelf, who took it, what it cost the ward or clinic, and the supplier orders and stocktakes in between.",
|
||||
offers: live
|
||||
? [
|
||||
{ "@type": "Offer", name: "Community — self-hosted", price: "0", priceCurrency: "AUD", availability: "https://schema.org/InStock" },
|
||||
{ "@type": "Offer", name: `Hosted Small — up to ${PRICES.freeStaff} staff records`, price: "0", priceCurrency: "AUD", availability: "https://schema.org/InStock" },
|
||||
{ "@type": "Offer", name: "Hosted Facility — a year", price: String(PRICES.hostedAnnual), priceCurrency: "AUD", availability: "https://schema.org/InStock", url: `${SITE}/pricing` },
|
||||
{ "@type": "Offer", name: `Health Service — up to ${PRICES.healthServiceFacilities} facilities, a year`, price: String(PRICES.healthServiceAnnual), priceCurrency: "AUD", availability: "https://schema.org/InStock", url: `${SITE}/pricing` },
|
||||
]
|
||||
: {
|
||||
"@type": "Offer",
|
||||
price: "0",
|
||||
priceCurrency: "AUD",
|
||||
availability: "https://schema.org/InStock",
|
||||
},
|
||||
featureList: [
|
||||
"Stock on hand by size",
|
||||
"Issue to a staff member against their entitlement",
|
||||
"Barcode scanning with a USB scanner or a phone camera",
|
||||
"Stocktakes by shelf with variance reasons",
|
||||
"Supplier orders, deliveries and back orders",
|
||||
"Cost centre reporting for finance",
|
||||
],
|
||||
});
|
||||
|
||||
export function faqPage(entries: { q: string; a: string }[]) {
|
||||
return {
|
||||
"@type": "FAQPage",
|
||||
"@id": `${SITE}/faq#faq`,
|
||||
mainEntity: entries.map(({ q, a }) => ({
|
||||
"@type": "Question",
|
||||
name: q,
|
||||
acceptedAnswer: { "@type": "Answer", text: a },
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
/** Wraps whatever is passed in the single @graph envelope crawlers prefer. */
|
||||
export function graph(...nodes: object[]) {
|
||||
return { "@context": "https://schema.org", "@graph": nodes };
|
||||
}
|
||||
Reference in New Issue
Block a user