# Component Model and Schema

## Components

Components are JSON objects that may be parts of other entities (e.g. [Pages](https://api.developer.placewise.com/doc-341710.md)). 

There are system-wide, predefined [System Components](https://api.developer.placewise.com/doc-344559.md), but it's possible to define own components with [Custom Components](https://api.developer.placewise.com/doc-341712.md) API.

### Example component

```
{
    // Common properties:
    "type": "social_feed",
    "visible_until": "2024-09-19T11:01:00+0200",
    "visible_since": "2024-09-12T11:00:00+0200",
    "title": { "en": "Title", "pl": null },
    // Properties specific for type:
    "sub_title": { "en": "Subtitle", "pl": "Podtytuł" },
    "api_key": "123123",
    "feed_id": "123123",
    "container_id": "123123"
}
```

### Common component properties

| Property      | Type                                                                                           | Required? | Description                                                 | 
|---------------|---------------------------------------------------------------------------|-----------|-------------------------------------------------------------|
| type          | enum                                                                                | yes       | Depends on current schema                                                         |
| visible_since | datetime                                                                                       | no        | If present, determines start of component visibility period |
| visible_until | datetime                                                                                       | no        | If present, determines end of component visibility period   |
| title         | [LocalizedContent](doc-341959#localizedcontent-json-model) | no        |                                                             |

## Component Schema

Component Schema is a [JSON Schema](https://json-schema.org/) that describes component model.

It is built by the [API](https://api.developer.placewise.com/api-3511179.md) based on currently implemented System Components, Custom Components configured per Customer/Website and on general Customer/Website configuration.

It is based on polymorphism - applies to each component treated as an object that, depending on its `type`, will have different set of properties.

### Example

This is a simplified version of typical schema. The purpose of it is to demonstrate and describe the general idea. Please note the comments that describe specific elements and behaviours.

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$defs": {

    // $attributes may be treated as a "library" of standard properties for components

    "$attributes": {
      "text": {
        "type": ["object", "null"], "additionalProperties": false, "required": ["en"], // Implied from main website language
        "properties": {
          // Actual set of translation keys depends on customer/website configuration
          "en": { "type": "string", "minLength": 1, "maxLength": 50000 },
          "pl": {"type": ["string", "null"], "maxLength": 50000 }
        }
      },
      "html": {
        "type": ["object", "null"], "additionalProperties": false, "required": ["en"],
        "properties": {
          "en": { "type": "string", "minLength": 1, "maxLength": 50000 },
          "pl": {"type": ["string", "null"], "maxLength": 50000 }
        }
      },
      "image": {
        "type": ["object", "null"], "additionalProperties": false, "required": [ "url" ],
        "properties": { "url": { "type": "string", "format": "website-url", "minLength": 1 } }
      },
      "link": {
        "type": ["object", "null"], "additionalProperties": false,
        "properties": {
          "text": { "$ref": "#/$defs/$attributes/text" },
          "url": { "type": [ "string","null"], "format": "website-url", "minLength": 1 },
          "target": { "type": ["string", "null"], "enum": ["self","blank","parent","top"], "default": "self" }
        }
      },
      //
      // (...)
      // 
    },
    // This contains definitions of specific types of components
    "$components": {
      //
      // (...)
      //
      // Service page component
      "article_container": {
        // Describes where the component may be utilized. Current options are:
        //   * page      For Pages
        //   * layout    For Website Layout
        //   * general   For Both 
        "$purpose": "general",
        // Determines which platforms (web, mobile) are supported by the component
        "$platforms": ["web"],
        // $title and $description are used to describe purpose of the component to users
        "$title": "Article container",
        "$description": "",
        // When present, it means that component is dedicated for page for specific service(s)
        "$page_services": ["article_page"],
        "required": [],
        "additionalProperties": false,
        "properties": {
          "title": { "$ref": "#/$defs/$attributes/text" },
          // JSON Schema mechanisms require these common attributes to be present in each component instance
          "type": true,
          "visible_since": true,
          "visible_until": true
        }
      },
      //
      // (...)
      //
      // A layout component
      "footer_1": {
        "$purpose": "layout",
        "$platforms": ["web"],
        "$title": "Footer",
        "$description": "Elements which appear in the footer of the page.",
        "$page_services": [],
        "required": [ "call_to_action_1", "links_1", "call_to_action_2", "social_media", "links_2" ],
        "additionalProperties": false,
        "properties": {
          "call_to_action_1": { "$ref": "#/$defs/$attributes/link" },
          "links_1": { "$ref": "#/$defs/$attributes/menu" },
          "call_to_action_2": { "$ref": "#/$defs/$attributes/link" },
          "social_media": { "const": true },
          "links_2": { "$ref": "#/$defs/$attributes/menu" },
          "type": true,
          "visible_since": true,
          "visible_until": true
        }
      },
      //
      // (...)
      //
      // A generic component
      "gallery": {
        "$purpose": "page",
        "$platforms": ["web"],
        "$title": "Gallery",
        "$description": "A photo grid that allows to download a photo or display it in a modal.",
        "$page_services": [],
        "required": [],
        "additionalProperties": false,
        "properties": {
          "title": { "$ref": "#/$defs/$attributes/text" },
          "download": { "type": "string" },
          "images": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": { "image": { "$ref": "#/$defs/$attributes/image" } },
              "additionalProperties": false
            }
          },
          "type": true,
          "visible_since": true,
          "visible_until": true
        }
      },
      //
      // (...)
      //
      // Another generic component
      "html_block": {
        "$purpose": "general",
        "$platforms": ["web"],
        "$title": "Rich text",
        "$description": "Allows you to add stylized text inline, optionally with photos or links.",
        "$page_services": [],
        "required": [],
        "additionalProperties": false,
        "properties": {
          "title": { "$ref": "#/$defs/$attributes/text" },
          "body": { "$ref": "#/$defs/$attributes/html" },
          "type": true,
          "visible_since": true,
          "visible_until": true
        }
      },
      //
      // (...)
      //
      // A custom component
      "links_list": {
        "$purpose": "page",
        "$platforms": ["web"],
        "$title": "List of links",
        "$description": "",
        "$page_services": [],
        "required": ["title"],
        "properties": {
          "links": {
            "type": "array",
            "items": {
              "type": "object", "required": ["text"],
              "properties": {
                "url": { "type": "string", "format": "website-url", "minLength": 1 },
                "text": { "$ref": "#/$defs/$attributes/text" }
              },
              "additionalProperties": false
            }
          },
          "title": { "$ref": "#/$defs/$attributes/text" },
          "type": true,
          "visible_since": true,
          "visible_until": true
        },
        "additionalProperties": false
      }
    }
  },

  // The Actual Component Schema starts here

  "type": "object",
  "properties": {
    // Common component attributes
    "type": { "type": "string", "enum": ["article_container", "footer_1", "gallery", "html_block", "links_list"] },
    "visible_since": { "type": ["string", "null" ], "format": "date-time" },
    "visible_until": { "type": [ "string", "null" ], "format": "date-time" }
  },
  "required": ["type"],
  // Depending on the `type` property, the base component definition gets extended with specific properties 
  "allOf": [
    // (...)
    {
      "if": { "properties": { "type": { "const": "article_container" } } },
      "then": { "$ref": "#/$defs/$components/article_container" }
    },
    // (...)
    {
      "if": { "properties": { "type": { "const": "footer_1" } } },
      "then": { "$ref": "#/$defs/$components/footer_1" }
    },
    // (...)
    {
      "if": { "properties": { "type": { "const": "gallery" } } },
      "then": { "$ref": "#/$defs/$components/gallery" }
    },
    // (...)
    {
      "if": { "properties": { "type": { "const": "html_block" } } },
      "then": { "$ref": "#/$defs/$components/html_block" }
    },
    // (...)
    {
      "if": { "properties": { "type": { "const": "links_list" } } },
      "then": { "$ref": "#/$defs/$components/links_list" }
    }
  ]
}
```
