(fix) Umbau zu SCS
This commit is contained in:
@@ -37,11 +37,22 @@ kotlin {
|
||||
jsMain.dependencies {
|
||||
// Kotlin React dependencies with explicit stable versions
|
||||
implementation("org.jetbrains.kotlin-wrappers:kotlin-react:18.2.0-pre.467")
|
||||
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom:18.2.0-pre.467")
|
||||
implementation("org.jetbrains.kotlin-wrappers:kotlin-emotion:11.10.5-pre.467")
|
||||
|
||||
// Ktor client dependencies for API calls
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.js)
|
||||
implementation(libs.ktor.client.contentNegotiation)
|
||||
implementation(libs.ktor.client.serializationKotlinxJson)
|
||||
|
||||
// Coroutines for async operations
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
|
||||
// NPM dependencies
|
||||
implementation(npm("react", "18.2.0"))
|
||||
implementation(npm("react-dom", "18.2.0"))
|
||||
implementation(npm("@r2wc/react-to-web-component", "2.0.4"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import at.mocode.masterdata.ui.components.StammdatenListe
|
||||
import react.create
|
||||
|
||||
/**
|
||||
* Main entry point for the Master Data JavaScript build.
|
||||
*
|
||||
* This function serves as the entry point for the Kotlin/JS application.
|
||||
* It registers the React component as a web component using r2wc.
|
||||
*/
|
||||
fun main() {
|
||||
console.log("Master Data JS module loaded successfully!")
|
||||
|
||||
// Import r2wc function from @r2wc/react-to-web-component npm package
|
||||
val r2wc = js("require('@r2wc/react-to-web-component')")
|
||||
|
||||
// Convert React component to Web Component using r2wc
|
||||
val StammdatenListeWebComponent = r2wc(StammdatenListe, js("{}"))
|
||||
|
||||
// Register the new component with a custom HTML tag
|
||||
js("customElements.define('stammdaten-liste', arguments[0])")(StammdatenListeWebComponent)
|
||||
|
||||
console.log("Web component 'stammdaten-liste' registered successfully!")
|
||||
console.log("You can now use <stammdaten-liste></stammdaten-liste> in your HTML")
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
package at.mocode.masterdata.ui.components
|
||||
|
||||
import at.mocode.masterdata.domain.model.LandDefinition
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.Json
|
||||
import react.*
|
||||
import react.dom.html.ReactHTML.div
|
||||
import react.dom.html.ReactHTML.h1
|
||||
import react.dom.html.ReactHTML.h2
|
||||
import react.dom.html.ReactHTML.h3
|
||||
import react.dom.html.ReactHTML.p
|
||||
import react.dom.html.ReactHTML.span
|
||||
import emotion.react.css
|
||||
|
||||
/**
|
||||
* Props for the StammdatenListe component
|
||||
*/
|
||||
external interface StammdatenListeProps : Props
|
||||
|
||||
// Create Ktor client for API calls
|
||||
private val apiClient = HttpClient {
|
||||
install(ContentNegotiation) {
|
||||
json(Json {
|
||||
ignoreUnknownKeys = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* React component that displays master data (Stammdaten).
|
||||
*
|
||||
* This component loads master data from the API and renders it as HTML.
|
||||
* Currently focuses on countries (LandDefinition) but can be extended for other master data types.
|
||||
* Uses useState for state management and useEffectOnce for data loading.
|
||||
*/
|
||||
val StammdatenListe = FC<StammdatenListeProps> { _ ->
|
||||
// State management with useState
|
||||
var countries by useState<List<LandDefinition>>(emptyList())
|
||||
var loading by useState(true)
|
||||
var error by useState<String?>(null)
|
||||
|
||||
// Data loading with useEffectOnce hook
|
||||
useEffectOnce {
|
||||
val scope = MainScope()
|
||||
scope.launch {
|
||||
try {
|
||||
loading = true
|
||||
error = null
|
||||
// Load data with Ktor client
|
||||
val response = apiClient.get("http://localhost:8080/api/masterdata/countries")
|
||||
val loadedCountries: List<LandDefinition> = response.body()
|
||||
countries = loadedCountries
|
||||
} catch (e: Exception) {
|
||||
error = "Fehler beim Laden der Stammdaten: ${e.message}"
|
||||
console.error("Error loading master data:", e)
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render HTML with React DOM elements
|
||||
div {
|
||||
css {
|
||||
// Basic styling for the main container
|
||||
"padding" to "20px"
|
||||
"fontFamily" to "Arial, sans-serif"
|
||||
"maxWidth" to "1200px"
|
||||
"margin" to "0 auto"
|
||||
}
|
||||
|
||||
h1 {
|
||||
css {
|
||||
"color" to "#2c3e50"
|
||||
"borderBottom" to "2px solid #3498db"
|
||||
"paddingBottom" to "10px"
|
||||
"marginBottom" to "20px"
|
||||
}
|
||||
+"Stammdaten"
|
||||
}
|
||||
|
||||
h2 {
|
||||
css {
|
||||
"color" to "#34495e"
|
||||
"marginTop" to "20px"
|
||||
"marginBottom" to "15px"
|
||||
"fontSize" to "1.5em"
|
||||
}
|
||||
+"Länder"
|
||||
}
|
||||
|
||||
when {
|
||||
loading -> {
|
||||
div {
|
||||
css {
|
||||
"padding" to "20px"
|
||||
"textAlign" to "center"
|
||||
"color" to "#666"
|
||||
"fontSize" to "18px"
|
||||
}
|
||||
+"Lade Stammdaten..."
|
||||
}
|
||||
}
|
||||
error != null -> {
|
||||
div {
|
||||
css {
|
||||
"padding" to "20px"
|
||||
"textAlign" to "center"
|
||||
"color" to "#e74c3c"
|
||||
"backgroundColor" to "#fdeaea"
|
||||
"border" to "1px solid #e74c3c"
|
||||
"borderRadius" to "8px"
|
||||
"margin" to "20px 0"
|
||||
}
|
||||
+error!!
|
||||
}
|
||||
}
|
||||
countries.isEmpty() -> {
|
||||
div {
|
||||
css {
|
||||
"padding" to "20px"
|
||||
"textAlign" to "center"
|
||||
"color" to "#666"
|
||||
"backgroundColor" to "#f8f9fa"
|
||||
"border" to "1px solid #e0e0e0"
|
||||
"borderRadius" to "8px"
|
||||
"margin" to "20px 0"
|
||||
}
|
||||
+"Keine Länder verfügbar"
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
div {
|
||||
css {
|
||||
"display" to "grid"
|
||||
"gridTemplateColumns" to "repeat(auto-fill, minmax(300px, 1fr))"
|
||||
"gap" to "20px"
|
||||
}
|
||||
countries.forEach { country ->
|
||||
div {
|
||||
css {
|
||||
"border" to "1px solid #e0e0e0"
|
||||
"borderRadius" to "8px"
|
||||
"padding" to "15px"
|
||||
"backgroundColor" to "#f9f9f9"
|
||||
"boxShadow" to "0 2px 4px rgba(0,0,0,0.1)"
|
||||
"transition" to "transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out"
|
||||
"hover" to {
|
||||
"transform" to "translateY(-5px)"
|
||||
"boxShadow" to "0 5px 15px rgba(0,0,0,0.1)"
|
||||
}
|
||||
}
|
||||
h3 {
|
||||
css {
|
||||
"color" to "#3498db"
|
||||
"marginTop" to "0"
|
||||
"marginBottom" to "10px"
|
||||
"borderBottom" to "1px solid #e0e0e0"
|
||||
"paddingBottom" to "5px"
|
||||
}
|
||||
+country.nameDeutsch
|
||||
}
|
||||
|
||||
// ISO codes
|
||||
p {
|
||||
span {
|
||||
+"🌍"
|
||||
}
|
||||
+" ISO-Codes: ${country.isoAlpha2Code} / ${country.isoAlpha3Code}"
|
||||
country.isoNumerischerCode?.let { numCode ->
|
||||
+" / $numCode"
|
||||
}
|
||||
}
|
||||
|
||||
// English name if available
|
||||
country.nameEnglisch?.let { englishName ->
|
||||
p {
|
||||
span {
|
||||
+"🇬🇧"
|
||||
}
|
||||
+" Englischer Name: $englishName"
|
||||
}
|
||||
}
|
||||
|
||||
// EU/EWR membership
|
||||
val membershipInfo = mutableListOf<String>()
|
||||
country.istEuMitglied?.let { isEuMember ->
|
||||
if (isEuMember) membershipInfo.add("EU-Mitglied")
|
||||
}
|
||||
country.istEwrMitglied?.let { isEwrMember ->
|
||||
if (isEwrMember) membershipInfo.add("EWR-Mitglied")
|
||||
}
|
||||
|
||||
if (membershipInfo.isNotEmpty()) {
|
||||
p {
|
||||
span {
|
||||
+"🇪🇺"
|
||||
}
|
||||
+" Mitgliedschaft: ${membershipInfo.joinToString(", ")}"
|
||||
}
|
||||
}
|
||||
|
||||
// Status
|
||||
p {
|
||||
span {
|
||||
+"ℹ️"
|
||||
}
|
||||
+" Status: ${if (country.istAktiv) "Aktiv" else "Inaktiv"}"
|
||||
}
|
||||
|
||||
// Sort order if available
|
||||
country.sortierReihenfolge?.let { sortOrder ->
|
||||
p {
|
||||
span {
|
||||
+"🔢"
|
||||
}
|
||||
+" Sortierreihenfolge: $sortOrder"
|
||||
}
|
||||
}
|
||||
|
||||
// Coat of arms/flag URL if available
|
||||
country.wappenUrl?.let { flagUrl ->
|
||||
p {
|
||||
span {
|
||||
+"🏴"
|
||||
}
|
||||
+" Wappen/Flagge: $flagUrl"
|
||||
}
|
||||
}
|
||||
|
||||
// Creation and update dates
|
||||
p {
|
||||
span {
|
||||
+"📅"
|
||||
}
|
||||
+" Erstellt am: ${country.createdAt}"
|
||||
}
|
||||
|
||||
p {
|
||||
span {
|
||||
+"🔄"
|
||||
}
|
||||
+" Zuletzt geändert: ${country.updatedAt}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user