Last active
April 15, 2024 21:55
-
-
Save seangwright/21c9dac51882309b2fc8f1387770396b to your computer and use it in GitHub Desktop.
Xperience by Kentico - Embedded structured content and the power of custom data types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace DancingGoat; | |
public class Address | |
{ | |
public const string LIST_FIELD_TYPE = "addresslist"; | |
public string Street { get; set; } = ""; | |
public string City { get; set; } = ""; | |
public string StateProvince { get; set; } = ""; | |
public string PostalCode { get; set; } = ""; | |
public string Country { get; set; } = ""; | |
public string Phone { get; set; } = ""; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class AddressListFormComponent : FormComponent< | |
AddressListFormComponentProperties, | |
AddressListFormComponentClientProperties, | |
IEnumerable<Address>> | |
{ | |
public const string IDENTIFIER = "DancingGoat.FormComponent.AddressList"; | |
public override string ClientComponentName => "@acme/web-admin/AddressList"; | |
} | |
public class AddressListFormComponentProperties | |
: FormComponentProperties { } | |
public class AddressListFormComponentClientProperties | |
: FormComponentClientProperties<IEnumerable<Address>> | |
{ | |
public Address NewAddress { get; } = new Address(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FormComponentProps } from "@kentico/xperience-admin-base"; | |
import { Input } from "@kentico/xperience-admin-components"; | |
import React, { ChangeEvent, useState } from "react"; | |
type Address = { | |
street: string; | |
city: string; | |
stateProvince: string; | |
postalCode: string; | |
country: string; | |
phone: string; | |
}; | |
interface AddressListFormComponentProps extends FormComponentProps { | |
newAddress: Address; | |
value: Address[]; | |
} | |
export const AddressListFormComponent = ( | |
props: AddressListFormComponentProps | |
) => { | |
const [addresses, setAddresses] = useState( | |
props.value ?? [{ ...props.newAddress }] | |
); | |
const handleFieldChange = ( | |
index: number, | |
event: ChangeEvent<HTMLInputElement> | |
) => { | |
if (props.onChange) { | |
const field = event.target.name.replace(`${index}-`, "") as keyof Address; | |
const updatedAddress = { | |
...addresses[index], | |
[field]: event.target.value, | |
}; | |
const updatedAddresses = addresses.map((a, i) => | |
i === index ? updatedAddress : a | |
); | |
setAddresses(updatedAddresses); | |
props.onChange(updatedAddresses); | |
} | |
}; | |
const handleDeleteAddress = (index: number) => { | |
if (props.onChange) { | |
const updatedAddresses = addresses.filter((a, i) => i !== index); | |
setAddresses(updatedAddresses); | |
props.onChange(updatedAddresses); | |
} | |
}; | |
const handleAddressAdd = () => { | |
if (props.onChange) { | |
const updatedAddresses = [...addresses, { ...props.newAddress }]; | |
setAddresses(updatedAddresses); | |
props.onChange(updatedAddresses); | |
} | |
}; | |
const fieldStyle = { marginTop: ".5rem" }; | |
return ( | |
<div> | |
{addresses.map((address, index) => ( | |
<div | |
key={index} | |
style={{ | |
marginTop: "2rem", | |
color: "var(--color-text-default-on-light)", | |
}} | |
> | |
<label>Address {index + 1}</label> | |
<div | |
style={{ | |
display: "grid", | |
gridTemplateColumns: "1fr 1fr", | |
gap: "1rem", | |
}} | |
> | |
<div style={fieldStyle}> | |
<Input | |
label="Street" | |
name={`${index}-street`} | |
value={address.street} | |
onChange={(e) => handleFieldChange(index, e)} | |
/> | |
</div> | |
<div style={fieldStyle}> | |
<Input | |
label="City" | |
name={`${index}-city`} | |
value={address.city} | |
onChange={(e) => handleFieldChange(index, e)} | |
/> | |
</div> | |
<div style={fieldStyle}> | |
<Input | |
label="State/Province" | |
name={`${index}-stateProvince`} | |
value={address.stateProvince} | |
onChange={(e) => handleFieldChange(index, e)} | |
/> | |
</div> | |
<div style={fieldStyle}> | |
<Input | |
label="Postal Code" | |
name={`${index}-postalCode`} | |
value={address.postalCode} | |
onChange={(e) => handleFieldChange(index, e)} | |
/> | |
</div> | |
<div style={fieldStyle}> | |
<Input | |
label="Country" | |
name={`${index}-country`} | |
value={address.country} | |
onChange={(e) => handleFieldChange(index, e)} | |
/> | |
</div> | |
<div style={fieldStyle}> | |
<Input | |
label="Phone" | |
name={`${index}-phone`} | |
value={address.phone} | |
onChange={(e) => handleFieldChange(index, e)} | |
/> | |
</div> | |
<div style={fieldStyle}> | |
<button | |
onClick={() => handleDeleteAddress(index)} | |
style={{ marginTop: "10px" }} | |
> | |
Remove | |
</button> | |
</div> | |
</div> | |
</div> | |
))} | |
<button onClick={handleAddressAdd} style={{ marginTop: "20px" }}> | |
Add Address | |
</button> | |
</div> | |
); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using DancingGoat; | |
[assembly: RegisterModule(typeof(CustomDataTypeModule))] | |
namespace DancingGoat; | |
public class CustomDataTypeModule : Module | |
{ | |
public CustomDataTypeModule() : base(nameof(CustomDataTypeModule)) { } | |
protected override void OnPreInit(ModulePreInitParameters parameters) | |
{ | |
DataTypeManager.RegisterDataTypes( | |
new DataType<IEnumerable<Address>>( | |
sqlType: "nvarchar(max)", | |
fieldType: Address.LIST_FIELD_TYPE, | |
schemaType: "xs:string", | |
conversionFunc: JsonDataTypeConverter.ConvertToModels, | |
dbConversionFunc: JsonDataTypeConverter.ConvertToString, | |
textSerializer: new DefaultDataTypeTextSerializer(Address.LIST_FIELD_TYPE)) | |
{ | |
TypeAlias = "Address", | |
SqlValueFormat = DataTypeManager.UNICODE, | |
DbType = SqlDbType.NVarChar, | |
DefaultValueCode = "[]", | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment