{"id":19060,"date":"2022-01-30T04:40:11","date_gmt":"2022-01-30T03:40:11","guid":{"rendered":"http:\/\/blog.wenzlaff.de\/?p=19060"},"modified":"2023-08-20T14:55:19","modified_gmt":"2023-08-20T12:55:19","slug":"single-page-webanwendung-spa-twkrankenhaus-app-mit-typescript-react-und-patternfly","status":"publish","type":"post","link":"http:\/\/blog.wenzlaff.de\/?p=19060","title":{"rendered":"Single-Page-Webanwendung (SPA): TWKrankenhaus App mit TypeScript, React und Patternfly"},"content":{"rendered":"<p>Ziel ist es eine Beispiel <a href=\"https:\/\/de.wikipedia.org\/wiki\/Single-Page-Webanwendung\" rel=\"noopener\" target=\"_blank\">SPA<\/a> TWKrankenhaus zu implementiern die <a href=\"https:\/\/www.typescriptlang.org\/\" rel=\"noopener\" target=\"_blank\">TypeScript<\/a>, <a href=\"https:\/\/react.dev\/\" rel=\"noopener\" target=\"_blank\">React<\/a> mit <a href=\"https:\/\/www.patternfly.org\/\" rel=\"noopener\" target=\"_blank\">Patternfly<\/a> nutzt. So das man ein Template f\u00fcr weitere Apps hat. <\/p>\n<p>Entweder man clont das ganze Projekt wie unten beschrieben oder man folgt allen Schritte. So soll es mal mit Mock-Test-Daten aussehen:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0.png\" alt=\"\" width=\"2452\" height=\"2186\" class=\"aligncenter size-full wp-image-19062\" srcset=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0.png 2452w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-300x267.png 300w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-1024x913.png 1024w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-768x685.png 768w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-1536x1369.png 1536w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-2048x1826.png 2048w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>1. In einem leern Verzeichnis, ein TypeScript Projekt mit Template anlegen: &#8230;<!--more--><\/p>\n<pre class=\"lang:default decode:true \" >\r\nnpx create-react-app twkrankenhaus --template typescript<\/pre>\n<p>Jetzt ist das Projekt schon lauff\u00e4hig, man kann es starten mit:<br \/>\n<strong>cd twkrankenhaus <\/strong><br \/>\n<strong>npm start<\/strong><\/p>\n<p>es \u00f6ffnet sich ein Browser unter <strong>http:\/\/localhost:3000\/<\/strong> und die Anwendung l\u00e4uft:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/wenzlaff.de-2022-01-29-um-19.02.47.png\" alt=\"\" width=\"942\" height=\"736\" class=\"aligncenter size-full wp-image-19061\" srcset=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/wenzlaff.de-2022-01-29-um-19.02.47.png 942w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/wenzlaff.de-2022-01-29-um-19.02.47-300x234.png 300w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/wenzlaff.de-2022-01-29-um-19.02.47-768x600.png 768w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>oder f\u00fcr die Produktion bauen mit <strong>npm run build<\/strong><\/p>\n<p>2. nun nicht verwendet Dateien l\u00f6schen und Referenzen anpassen<\/p>\n<pre class=\"lang:default decode:true \" >rm public\/favicon.ico public\/logo192.png public\/logo512.png public\/robots.txt public\/manifest.json src\/logo.svg src\/App.test.tsx src\/reportWebVitals.ts src\/setupTests.ts src\/react-app-env.d.ts<\/pre>\n<p>Es wird jetzt eine Seite mit TWKrankenhaus angezeigt.<\/p>\n<p>3. Json Testdaten <strong>krhs.json<\/strong> in das <strong>src<\/strong> Verzeichnis hinzuf\u00fcgen. Kann wie <a href=\"http:\/\/blog.wenzlaff.de\/?p=19044\" rel=\"noopener\" target=\"_blank\">hier<\/a> beschrieben erzeugt werden oder aus dem <a href=\"https:\/\/gitlab.com\/IT-Berater\/twkrankenhaus\/-\/tree\/main\/src\" rel=\"noopener\" target=\"_blank\">Gitlab Projekt<\/a> kopiert werden.<\/p>\n<p>4. Patternfly hinzuf\u00fcgen<\/p>\n<pre class=\"lang:default decode:true \" >\r\nnpm install @patternfly\/react-core --save\r\nnpm install @patternfly\/patternfly --save<\/pre>\n<p>5. CSS Style erg\u00e4nzen in <strong>App.css<\/strong>, damit die Suchzeile etwas blau ist<\/p>\n<pre class=\"lang:css decode:true \" >.sucheleiste {\r\n  background: linear-gradient(to bottom, #5e1dec, #0298d5);\r\n  min-height: 10px;\r\n  display: flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n  justify-content: center;\r\n  font-size: calc(10px + 2vmin);\r\n  color: white;\r\n}\r\n<\/pre>\n<p>6. und die <strong>App.tsx<\/strong> wie folgt anpassen:<\/p>\n<p>Funktion f\u00fcr die unterschiedlichen Icons, je nach Krankenhaus:<\/p>\n<pre class=\"lang:js decode:true \" >function isKooperativ(wert:boolean){\r\n  if (wert){ \r\n    return &lt;CheckCircleIcon color=\"var(--pf-global--success-color--100)\" \/&gt;\r\n  }else{\r\n    return &lt;TimesCircleIcon color=\"var(--pf-global--danger-color--100)\" \/&gt;\r\n  }\r\n}<\/pre>\n<p>Zuerst die Suchzeile als Input-Feld definieren und dann je nach eingabe im Namen und den Suchbegriffen suchen und alles als eine <a href=\"https:\/\/www.patternfly.org\/\" rel=\"noopener\" target=\"_blank\">Gallery<\/a> anzeigen. Der Titel kann auch \u00fcber die ClipboardCopy Klasse in das Clipboard kopiert werden. Die Internet Adresse des Krankenhaus wird als Link eingef\u00fcgt:<\/p>\n<pre class=\"lang:js decode:true \" >export default function App() {\r\n  const [query, setQuery] = useState(\"\");\r\n  return (\r\n    &lt;&gt;\r\n      &lt;div className=\"sucheleiste\"&gt;\r\n      &lt;p&gt;Krankenhaus Suche&lt;\/p&gt;\r\n      &lt;input\r\n        placeholder=\"Suchbegriff eingeben\"\r\n        onChange={(event) =&gt; setQuery(event.target.value)}\r\n      \/&gt;\r\n      &lt;\/div&gt;\r\n     &lt;Gallery&gt;\r\n        {Data.filter((post) =&gt; {\r\n          if (query === \"\") {\r\n            return post;\r\n          } else if (post.krhsName.toLowerCase().includes(query.toLowerCase()) || post.krhsSuchbegriffe.toLowerCase().includes(query.toLowerCase()) ) {\r\n            return post;\r\n          }\r\n        }).map((post, index) =&gt; (\r\n          &lt;div key={index}&gt;\r\n            &lt;Card&gt;\r\n              &lt;CardTitle&gt;{post.krhsId}. {&lt;ClipboardCopy hoverTip=\"Kopieren\" clickTip=\"Kopiert\" variant=\"inline-compact\"&gt;{post.krhsName}&lt;\/ClipboardCopy&gt;}&lt;\/CardTitle&gt;\r\n              &lt;CardBody&gt;\r\n                &lt;DescriptionList&gt;\r\n                  &lt;DescriptionListGroup&gt;  \r\n                   &lt;DescriptionListTerm&gt;\r\n                    &lt;Flex flexWrap={{ default: 'nowrap' }}&gt;\r\n                      &lt;FlexItem&gt;                       \r\n                        {isKooperativ(post.krhsKooperativ)} {post.krhsFachgebiete}\r\n                      &lt;\/FlexItem&gt;\r\n                    &lt;\/Flex&gt;\r\n                    &lt;\/DescriptionListTerm&gt;\r\n                  &lt;\/DescriptionListGroup&gt;  \r\n                  &lt;Divider \/&gt;\r\n                  &lt;DescriptionListGroup&gt;               \r\n                    &lt;DescriptionListTerm&gt;{post.krhsStr}&lt;\/DescriptionListTerm&gt;\r\n                    &lt;DescriptionListTerm&gt;{post.krhsPlz} {post.krhsOrt}&lt;\/DescriptionListTerm&gt;                  \r\n                    &lt;DescriptionListDescription&gt;&lt;a href={post.krhsUrl}&gt;Link ...&lt;\/a&gt;&lt;\/DescriptionListDescription&gt;\r\n                  &lt;\/DescriptionListGroup&gt;\r\n                &lt;\/\u00a0DescriptionList&gt;\r\n              &lt;\/CardBody&gt;\r\n              &lt;Divider \/&gt;\r\n              &lt;CardFooter&gt;{post.krhsSuchbegriffe}&lt;\/CardFooter&gt;\r\n            &lt;\/Card&gt;\r\n          &lt;\/div&gt;\r\n        ))}\r\n      &lt;\/Gallery&gt;\r\n    &lt;\/&gt;\r\n  );\r\n}<\/pre>\n<p>Nach einem <strong>npm run start<\/strong>, l\u00e4uf es wie gew\u00fcnscht (siehe Tag v.0.0.3 im Git-Repo):<\/p>\n<p>7. Patternfly CSS erg. und index.html angepasst damit es etwas sch\u00f6ner aussieht.<\/p>\n<p>Das Ergebnis (siehe Tag v0.0.4):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0.png\" alt=\"\" width=\"2452\" height=\"2186\" class=\"aligncenter size-full wp-image-19062\" srcset=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0.png 2452w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-300x267.png 300w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-1024x913.png 1024w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-768x685.png 768w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-1536x1369.png 1536w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2022\/01\/twkrankenhaus-1.0-2048x1826.png 2048w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>Das ganze Projekt, kann auch mit<\/p>\n<pre class=\"lang:default decode:true \" >git clone https:\/\/gitlab.com\/IT-Berater\/twkrankenhaus.git\r\ncd twkrankenhaus\r\nnpm install @patternfly\/react-core\r\nnpm install @patternfly\/patternfly \r\nnpm run start\r\n<\/pre>\n<p>lokal geladen und gestartet werden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ziel ist es eine Beispiel SPA TWKrankenhaus zu implementiern die TypeScript, React mit Patternfly nutzt. So das man ein Template f\u00fcr weitere Apps hat. Entweder man clont das ganze Projekt wie unten beschrieben oder man folgt allen Schritte. So soll es mal mit Mock-Test-Daten aussehen: 1. In einem leern Verzeichnis, ein TypeScript Projekt mit Template &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/blog.wenzlaff.de\/?p=19060\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eSingle-Page-Webanwendung (SPA): TWKrankenhaus App mit TypeScript, React und Patternfly\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[220,3137,5176,79],"tags":[2074,4947,5260],"class_list":["post-19060","post","type-post","status-publish","format-standard","hentry","category-anleitung","category-javascript","category-patternfly","category-programmierung","tag-krankenhaus","tag-spa","tag-twkrankenhaus"],"_links":{"self":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts\/19060","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=19060"}],"version-history":[{"count":0,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts\/19060\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=19060"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=19060"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=19060"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}