Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | import * as React from "react"; import { Box, Button, Flash, Form } from "rimble-ui"; import { colors } from "../../../../themes"; import { WorkingSchema, newSchemaAttribute, defaultSchemaProperties } from "../types"; import { SchemaAttribute } from "./SchemaAttribute"; export interface AttributesStepProps { schema: WorkingSchema; updateSchema(updates: Partial<WorkingSchema>): void; onComplete(): void; } export const AttributesStep: React.FunctionComponent<AttributesStepProps> = (props) => { const { schema, updateSchema } = props; const [doValidation, setDoValidation] = React.useState(false); const [error, setError] = React.useState(""); function addAttribute(e: Event) { if (schema.properties?.credentialSubject?.properties?.[""]) { // We have a property with no name - have them update that before creating a no one. We don't have to do anything, since the un-preventDefaulted event will trigger browser UI on empty required title field return; } e.preventDefault(); updateSchema({ ...schema, properties: { ...schema.properties, credentialSubject: { ...schema.properties?.credentialSubject, properties: { ...schema.properties?.credentialSubject?.properties, "": { ...newSchemaAttribute }, }, }, }, }); } function goNext(e: Event) { e.preventDefault(); setError(""); const propertyIds = new Set(); let missingField = false; let duplicateId = false; let invalidId = false; // @TODO/tobek These checks should be recursive. Empty `title`'s are already handled by native browser form checks, but `$linkedData.term` collisions (which would have to be unique only among sibling properties) are not handled. Object.entries(schema.properties?.credentialSubject?.properties || {}).forEach(([key, prop]) => { if (key === "") { missingField = true; } if (prop.$linkedData?.term) { if (prop.$linkedData?.term === "type") { setError( `An attribute name result in ID "${prop.$linkedData.term}" - this is a reserved keyword in the JSON-LD specification that VCs use. Please use a different name.`, ); invalidId = true; } else if (propertyIds.has(prop.$linkedData.term)) { setError( `Two attribute names result in ID "${prop.$linkedData.term}" - all attributes must have unique IDs.`, ); duplicateId = true; } else { propertyIds.add(prop.$linkedData.term); } } }); if (missingField || duplicateId || invalidId) { setDoValidation(true); } else { setDoValidation(false); props.onComplete(); } } return ( <Form validated={doValidation} onSubmit={goNext}> {defaultSchemaProperties.map((prop, i) => ( <SchemaAttribute key={i + "required"} attr={prop} readOnly={true} parentRequired={["issuanceDate", "issuer"]} /> ))} {schema.properties?.credentialSubject && ( <SchemaAttribute key={"credentialSubject"} attr={schema.properties.credentialSubject} isCredSubject updateAttribute={(attr) => { updateSchema({ ...schema, properties: { ...schema.properties, credentialSubject: attr, }, }); }} /> )} <Box mt={3}> <Button.Outline mb={3} mx="auto" type="submit" width="100%" onClick={addAttribute} style={{ borderColor: colors.primary.base }} > Add Another Attribute </Button.Outline> {error && ( <Flash mb={3} variant="danger"> Error: {error} </Flash> )} <Button type="submit" width="100%"> Review </Button> </Box> </Form> ); }; |