Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
alaust-dev committed Jun 26, 2023
1 parent 97f6cc8 commit 095f557
Show file tree
Hide file tree
Showing 19 changed files with 221 additions and 38 deletions.
31 changes: 31 additions & 0 deletions mappings/GET_samle-webseite_sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"request": {
"method": "GET",
"url": "/sample-webseite/sample"
},
"response": {
"status": 200,
"jsonBody": {
"name": "sample",
"preview": "",
"multilanguage": true,
"singleType": false,
"allowedMethods": [
"GET"
],
"fields": [
{
"name": "name",
"required": true,
"deletable": false,
"type": "TEXT",
"maxLength": -1,
"defaultText": ""
}
]
},
"headers": {
"Content-Type": "application/json"
}
}
}
15 changes: 15 additions & 0 deletions mappings/GET_sample-webseite.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"request": {
"method": "GET",
"url": "/sample-webseite"
},
"response": {
"status": 200,
"jsonBody": [
"sample"
],
"headers": {
"Content-Type": "application/json"
}
}
}
File renamed without changes.
File renamed without changes.
24 changes: 16 additions & 8 deletions src/components/admin/content-type/content_type_holder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import ContentTypeItem from "@/components/admin/content-type/content_type_item";
import PrimaryButton from "@/components/core/input/primary_button";
import List from "@/components/core/input/list";
import {useState} from "react";
import {ContentTypeEnum} from "@/models/enum/content_type_enum";
import {ContentType} from "@/models/content-type/content_type";

export default function ContentTypeHolder() {
export default function ContentTypeHolder({contentType}: ContentTypeHolderProps) {
const [open, setOpen] = useState(false)

return (
<>
{/* HEAD */}
<button onClick={() => setOpen(!open)}
className="flex items-center bg-admin-text text-admin-primary-background py-3 px-2 rounded-lg w-full">
<span>Game</span>
<span>{contentType.name}</span>
{open
? <GoTriangleUp className="ml-auto"/>
: <GoTriangleDown className="ml-auto"/>
Expand All @@ -26,21 +26,29 @@ export default function ContentTypeHolder() {
<div className="bg-admin-secondary-background p-4">
<div className="flex gap-4 items-start grow-0">
<div className="flex gap-4 w-[55%]">
<TextField title="Stage URL" placeholder="https://stage.your-website.net/blog"
className="w-[50%]"/>
<CheckBox title="Mehrsprachig"/>
<CheckBox title="Einzelner Typ"/>
<TextField title="Stage URL"
placeholder="https://stage.your-website.net/blog"
className="w-[50%]"
value={contentType.preview}/>
<CheckBox title="Mehrsprachig" checked={contentType.multilanguage}/>
<CheckBox title="Einzelner Typ" checked={contentType.singleType}/>
</div>
<div>
<List title="Erlaubte HTTP Methoden" values={["GET", "POST", "DELETE"]}/>
</div>
</div>
<div className="mt-4">
<ContentTypeItem name="name" type={ContentTypeEnum.TEXT} deletable={false}/>
{contentType.fields.map((field) => <ContentTypeItem key={field.name} field={field}/>)}
<PrimaryButton tittle="+ Neues Feld" classname="h-[40px] mt-24"/>
</div>
</div>
}
</>
)
}

export type ContentTypeHolderProps = {
contentType: ContentType
onNewField?: () => void
onDeleteField?: () => void
}
13 changes: 6 additions & 7 deletions src/components/admin/content-type/content_type_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import React from "react";
import {MdDeleteOutline, MdOutlineModeEdit} from "react-icons/md";
import {ContentTypeEnum} from "@/models/enum/content_type_enum";
import {getContentTypeDisplayData} from "@/util/content_type_util";
import {Field} from "@/models/content-type/field";

export default function ContentTypeItem({name, type, deletable}: ContentTypeItemProps) {
const data = getContentTypeDisplayData(type)
export default function ContentTypeItem({field}: ContentTypeItemProps) {
const data = getContentTypeDisplayData(ContentTypeEnum[field.type as keyof typeof ContentTypeEnum])

return (
<div className="flex items-center border-2 border-admin-text-secondary rounded-xl px-4 py-1">
Expand All @@ -15,7 +16,7 @@ export default function ContentTypeItem({name, type, deletable}: ContentTypeItem
</div>
<div className="flex flex-col items-center ml-10">
<span className="text-xs text-admin-text-secondary">Name</span>
<span className="text-sm">{name}</span>
<span className="text-sm">{field.name}</span>
</div>
<div className="flex flex-col items-center ml-10">
<span className="text-xs text-admin-text-secondary">Typ</span>
Expand All @@ -25,7 +26,7 @@ export default function ContentTypeItem({name, type, deletable}: ContentTypeItem
<button className="hover:opacity-50 ml-auto">
<MdOutlineModeEdit className="w-[24px] h-[24px]"/>
</button>
{(deletable ?? true)
{(field.deletable ?? true)
? <button className="hover:opacity-50 ml-auto"><MdDeleteOutline className="w-[24px] h-[24px]"/>
</button>
: <GoLock className="w-[21px] h-[21px]"/>
Expand All @@ -36,7 +37,5 @@ export default function ContentTypeItem({name, type, deletable}: ContentTypeItem
}

type ContentTypeItemProps = {
name: string
type: ContentTypeEnum
deletable?: boolean
field: Field
}
5 changes: 4 additions & 1 deletion src/components/admin/content-type/content_type_list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ export default function ContentTypeList({onChange}: ContentTypeListProps) {
if (!onChange) return
onChange(selectedOption)
setSelectedOptionData(getContentTypeDisplayData(selectedOption))
}, [selectedOption, onChange])

// Also adding onChange as dependency results in a maximum update depth exceeded
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedOption])

return (
<Listbox value={selectedOption} onChange={setSelectedOption}>
Expand Down
42 changes: 31 additions & 11 deletions src/components/admin/content-type/content_type_overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@ import TextField from "@/components/core/input/text_field";
import ContentTypeList from "@/components/admin/content-type/content_type_list";
import CheckBox from "@/components/core/input/check_box";
import TextSettings from "@/components/admin/content-type/settings/text_settings";
import {useState} from "react";
import {ChangeEvent, Dispatch, SetStateAction, useEffect, useState} from "react";
import {ContentTypeEnum} from "@/models/enum/content_type_enum";
import {Field} from "@/models/content-type/field";
import MediaSettings from "@/components/admin/content-type/settings/media_settings";
import ColorSettings from "@/components/admin/content-type/settings/color_settings";
import ListSettings from "@/components/admin/content-type/settings/list_settings";
import PrimaryButton from "@/components/core/input/primary_button";
import SecondaryButton from "@/components/core/input/secondary_button";
import _ from "lodash";
import {useStateWithField} from "@/hooks/use_state_with_field";

export default function ContentTypeOverlay({onClose}: ContentTypeOverlayProps) {
export default function ContentTypeOverlay({initField, onClose}: ContentTypeOverlayProps) {

const [settings, setSettings] = useState<undefined | JSX.Element>(<TextSettings/>)
const [field, setField] = useStateWithField({name: "", required: false})
const [field, setField] = useStateWithField<Field>(initField)

useEffect(() => {
console.log(field)
}, [field])

function updateSettings(type: ContentTypeEnum) {
switch (type) {
Expand All @@ -35,35 +43,47 @@ export default function ContentTypeOverlay({onClose}: ContentTypeOverlayProps) {
}
}

function updateName(event: ChangeEvent<HTMLInputElement>) {
const updatedField: Field = _.clone(field)
updatedField.name = event.currentTarget.value
setField(updatedField)
}

function updateRequired(event: ChangeEvent<HTMLInputElement>) {
const updatedField: Field = _.clone(field)
updatedField.required = Boolean(event.currentTarget.value)
setField(updatedField)
}

return (
<div className="absolute w-screen h-screen z-50 flex justify-center items-center">
<div className="absolute w-screen h-screen bg-admin-primary-background opacity-80 z-40"/>
<div className="absolute w-[90vw] h-[90vh] bg-admin-secondary-background z-50 rounded-lg overflow-y-scroll">
<div className="absolute flex flex-col w-[90vw] h-[90vh] bg-admin-secondary-background z-50 rounded-lg overflow-y-scroll">
<button className="absolute top-4 right-4" onClick={onClose}>
<ImCross className="w-[32px] h-[32px] hover:opacity-75"/>
</button>
<div className="flex flex-col gap-4 m-8 w-[25%]">
<h2 className="text-admin-text-secondary font-bold my-4">NEUER CONTENT TYP</h2>
<TextField title="Name" placeholder="your-content-type"/>
<TextField title="Name" placeholder="your-content-type" onChange={updateName} value={field.name}/>
<ContentTypeList onChange={updateSettings}/>
<CheckBox title="Erforderlich"/>
<CheckBox title="Erforderlich" onChange={updateRequired} checked={field.required}/>
</div>
{settings &&
<div className="flex flex-col gap-4 m-8 w-[25%]">
<h2 className="text-admin-text-secondary font-bold my-4">TYP EINSTELLUNGEN</h2>
{settings}
</div>
}
<div className="sticky self-end right-4 bottom-4 flex gap-4 w-[20%] mt-auto ml-auto ">
<PrimaryButton tittle="Speichern"/>
<SecondaryButton tittle="Abbrechen" onClick={onClose}/>
</div>
</div>
</div>
)
}

export type ContentTypeOverlayProps = {
initField: Field
onClose?: () => void
}

function useStateWithField<T extends Field>(value: T) {
const [field, setField] = useState<T>(value)
return [field, setField]
}
17 changes: 17 additions & 0 deletions src/components/core/input/secondary_button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";

export default function SecondaryButton({tittle, classname, onClick}: ButtonProps) {
return (
<button
className={`w-full p-3 rounded-lg bg-admin-primary-background hover:opacity-60 font-bold flex justify-center items-center ${classname ?? ''}`}
onClick={onClick}>
{tittle}
</button>
)
}

type ButtonProps = {
tittle: string
classname?: string
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void
}
2 changes: 2 additions & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const CONTENT_SERVING_SERVICE = "http://localhost:8080"
const CONTENT_MANAGING_SERVICE = "http://localhost:8080"
7 changes: 7 additions & 0 deletions src/hooks/use_state_with_field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {Field} from "@/models/content-type/field";
import {Dispatch, SetStateAction, useState} from "react";

export function useStateWithField<T extends Field>(value: T): [T, Dispatch<SetStateAction<T>>] {
const [field, setField] = useState<T>(value)
return [field, setField]
}
2 changes: 2 additions & 0 deletions src/models/content-type/field.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export type Field = {
name: string
required: boolean
deletable: boolean
type: string
}
2 changes: 1 addition & 1 deletion src/models/content-type/fields/number_field.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Field} from "@/models/content-type/field";

export type Number_field = Field & {
export type NumberField = Field & {
minValue: number
maxValue: number
}
26 changes: 23 additions & 3 deletions src/pages/admin/content-types/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,34 @@ import ContentTypeHolder from "@/components/admin/content-type/content_type_hold
import PrimaryButton from "@/components/core/input/primary_button";
import {getCookieValue} from "@/util/cookie_utils";
import ContentTypeOverlay from "@/components/admin/content-type/content_type_overlay";
import ContentRepository from "@/repositories/content_repository";
import {ContentType} from "@/models/content-type/content_type";
import _ from "lodash";
import {useStateWithField} from "@/hooks/use_state_with_field";

export default function SpaceSettings({
user,
spaces,
initCurrentSpace
initCurrentSpace,
contentTypes
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
const newEmptyField = () => _.clone({
name: "",
type: "TEXT",
required: false,
deletable: true,
defaultText: "",
maxLength: -1
})

const [current, setCurrent] = useState<Space>(initCurrentSpace)
const [isOverlayOpen, setOverlayOpen] = useState(true)
const [selectedField, setSelectedField] = useStateWithField(newEmptyField())

return (
<main className="flex min-h-screen">
{isOverlayOpen &&
<ContentTypeOverlay onClose={() => setOverlayOpen(false)}/>
<ContentTypeOverlay initField={selectedField} onClose={() => setOverlayOpen(false)}/>
}
<Sidebar user={user} spaces={
spaces.map((space: Space) => (
Expand All @@ -36,7 +50,9 @@ export default function SpaceSettings({
<h2 className="text-admin-text-secondary font-bold">CONTENT TYPEN</h2>
<TextField title="Suchen" placeholder="Deinen Suchtext..."/>
<div className="w-full">
<ContentTypeHolder/>
{contentTypes.map((type: ContentType) =>
<ContentTypeHolder key={type.name} contentType={type}/>)
}
</div>
<PrimaryButton tittle="+ Neuen Content Typ" classname="mt-14"/>
</div>
Expand All @@ -50,5 +66,9 @@ export const getServerSideProps: GetServerSideProps = (context) => {

props.spaces = await SpaceRepository.getAll(sessionCookie)
props.initCurrentSpace = await SpaceRepository.get(Number(context.query.id), sessionCookie)

const contentTypeNames = await ContentRepository.getTypes("sample-webseite", sessionCookie)
props.contentTypes = await Promise.all(contentTypeNames.map(async (name) =>
await ContentRepository.getType("sample-webseite", name, sessionCookie)))
})
}
6 changes: 3 additions & 3 deletions src/pages/admin/space-settings/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ export default function SpaceSettings({
{isUnsaved &&
<>
<div
className="fixed flex items-center gap-4 px-4 w-[75%] h-[5vh] bg-red-600 z-50 rounded-xl top-5 ml-9">
className="fixed flex items-center gap-4 px-4 w-[75%] h-[5vh] bg-admin-secondary-background z-50 rounded-xl top-5 ml-9">
Achtung! Ungespeicherte Inhalte {' '}
<button className="hover:underline ml-auto"
onClick={() => setCurrent(initCurrentSpace)}>Reset
onClick={() => setCurrent(initCurrentSpace)}>Zurücksetzen
</button>
<PrimaryButton tittle="Speichern" classname="w-[8%] h-[80%]" onClick={submit}/>
<PrimaryButton tittle="Speichern" classname="max-w-[100px] h-[80%] bg-green-600 hover:bg-green-5003" onClick={submit}/>
</div>
<div className="h-[5vh]"/>
</>
Expand Down
2 changes: 1 addition & 1 deletion src/repositories/auth_repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import InternalServerError from "@/exceptions/internal_server_error";
export default class AuthRepository {

public static async login(form: LoginForm): Promise<string> {
const response = await fetch("http://localhost:8080/login", {
const response = await fetch(`${CONTENT_MANAGING_SERVICE}/login`, {
method: "POST",
body: JSON.stringify(form)
})
Expand Down
Loading

0 comments on commit 095f557

Please sign in to comment.