diff --git a/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/ConerTrailerCliProcessFactory.kt b/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/ConerTrailerCliProcessFactory.kt
index 7ee802f09..8dca0cd41 100644
--- a/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/ConerTrailerCliProcessFactory.kt
+++ b/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/ConerTrailerCliProcessFactory.kt
@@ -1,6 +1,6 @@
package tech.coner.trailer.app.admin.util
-import tech.coner.trailer.Club
+import tech.coner.trailer.domain.entity.Club
import tech.coner.trailer.Event
import tech.coner.trailer.Participant
import tech.coner.trailer.Person
diff --git a/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/SubcommandArgumentsFactory.kt b/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/SubcommandArgumentsFactory.kt
index 62d218268..f75cc1855 100644
--- a/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/SubcommandArgumentsFactory.kt
+++ b/admin/src/integration-test/kotlin/tech/coner/trailer/app/admin/util/SubcommandArgumentsFactory.kt
@@ -5,6 +5,7 @@ import tech.coner.trailer.eventresults.EventResultsType
import java.nio.file.Path
import java.time.LocalDate
import java.util.*
+import tech.coner.trailer.domain.entity.Club
class SubcommandArgumentsFactory(
private val snoozleDir: Path,
diff --git a/core-test/src/main/kotlin/tech/coner/trailer/TestClubs.kt b/core-test/src/main/kotlin/tech/coner/trailer/TestClubs.kt
index 3df1e64c9..864fe054f 100644
--- a/core-test/src/main/kotlin/tech/coner/trailer/TestClubs.kt
+++ b/core-test/src/main/kotlin/tech/coner/trailer/TestClubs.kt
@@ -1,5 +1,7 @@
package tech.coner.trailer
+import tech.coner.trailer.domain.entity.Club
+
object TestClubs {
val lscc = Club(
name = "Local Sports Car Club"
diff --git a/core/pom.xml b/core/pom.xml
index 382c99b2d..7a192552c 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -11,4 +11,12 @@
4.0.0
core
+
+
+
+ tech.coner.trailer
+ toolkit-validation
+ 0.1.0-SNAPSHOT
+
+
\ No newline at end of file
diff --git a/core/src/main/kotlin/tech/coner/trailer/Policy.kt b/core/src/main/kotlin/tech/coner/trailer/Policy.kt
index 27da54665..3e2839d21 100644
--- a/core/src/main/kotlin/tech/coner/trailer/Policy.kt
+++ b/core/src/main/kotlin/tech/coner/trailer/Policy.kt
@@ -4,6 +4,7 @@ import tech.coner.trailer.eventresults.EventResultsType
import tech.coner.trailer.eventresults.FinalScoreStyle
import tech.coner.trailer.eventresults.PaxTimeStyle
import java.util.*
+import tech.coner.trailer.domain.entity.Club
data class Policy(
val id: UUID,
diff --git a/core/src/main/kotlin/tech/coner/trailer/Club.kt b/core/src/main/kotlin/tech/coner/trailer/domain/entity/Club.kt
similarity index 73%
rename from core/src/main/kotlin/tech/coner/trailer/Club.kt
rename to core/src/main/kotlin/tech/coner/trailer/domain/entity/Club.kt
index 2b4ac8033..68d3c3336 100644
--- a/core/src/main/kotlin/tech/coner/trailer/Club.kt
+++ b/core/src/main/kotlin/tech/coner/trailer/domain/entity/Club.kt
@@ -1,4 +1,4 @@
-package tech.coner.trailer
+package tech.coner.trailer.domain.entity
data class Club(
val name: String
diff --git a/core/src/main/kotlin/tech/coner/trailer/domain/validation/ClubFeedback.kt b/core/src/main/kotlin/tech/coner/trailer/domain/validation/ClubFeedback.kt
new file mode 100644
index 000000000..548d76632
--- /dev/null
+++ b/core/src/main/kotlin/tech/coner/trailer/domain/validation/ClubFeedback.kt
@@ -0,0 +1,18 @@
+package tech.coner.trailer.domain.validation
+
+import tech.coner.trailer.domain.entity.Club
+import tech.coner.trailer.toolkit.validation.Feedback
+import tech.coner.trailer.toolkit.validation.Severity
+
+sealed class ClubFeedback : Feedback {
+
+ override val severity = Severity.Error
+
+ data object NameMustNotBeBlank : ClubFeedback() {
+ override val property = Club::name
+ }
+
+ data object NameMustNotExceedMaxLength : ClubFeedback() {
+ override val property = Club::name
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/kotlin/tech/coner/trailer/domain/validation/ClubValidator.kt b/core/src/main/kotlin/tech/coner/trailer/domain/validation/ClubValidator.kt
new file mode 100644
index 000000000..3f5cc4bf5
--- /dev/null
+++ b/core/src/main/kotlin/tech/coner/trailer/domain/validation/ClubValidator.kt
@@ -0,0 +1,13 @@
+package tech.coner.trailer.domain.validation
+
+import tech.coner.trailer.domain.entity.Club
+import tech.coner.trailer.domain.validation.ClubFeedback.NameMustNotBeBlank
+import tech.coner.trailer.domain.validation.ClubFeedback.NameMustNotExceedMaxLength
+import tech.coner.trailer.toolkit.validation.Validator
+
+typealias ClubValidator = Validator
+
+fun ClubValidator() = Validator {
+ Club::name { name -> NameMustNotBeBlank.takeUnless { name.isNotBlank() } }
+ Club::name { name -> NameMustNotExceedMaxLength.takeUnless { name.length <= Club.NAME_MAX_LENGTH } }
+}
diff --git a/io/src/main/kotlin/tech/coner/trailer/io/constraint/ClubPersistConstraints.kt b/io/src/main/kotlin/tech/coner/trailer/io/constraint/ClubPersistConstraints.kt
index 89bce8fd2..9efff2ef3 100644
--- a/io/src/main/kotlin/tech/coner/trailer/io/constraint/ClubPersistConstraints.kt
+++ b/io/src/main/kotlin/tech/coner/trailer/io/constraint/ClubPersistConstraints.kt
@@ -1,6 +1,6 @@
package tech.coner.trailer.io.constraint
-import tech.coner.trailer.Club
+import tech.coner.trailer.domain.entity.Club
import tech.coner.trailer.toolkit.konstraints.CompositeConstraint
class ClubPersistConstraints : CompositeConstraint() {
diff --git a/io/src/main/kotlin/tech/coner/trailer/io/mapper/ClubMapper.kt b/io/src/main/kotlin/tech/coner/trailer/io/mapper/ClubMapper.kt
index 706ea2163..810a514f4 100644
--- a/io/src/main/kotlin/tech/coner/trailer/io/mapper/ClubMapper.kt
+++ b/io/src/main/kotlin/tech/coner/trailer/io/mapper/ClubMapper.kt
@@ -1,6 +1,6 @@
package tech.coner.trailer.io.mapper
-import tech.coner.trailer.Club
+import tech.coner.trailer.domain.entity.Club
import tech.coner.trailer.datasource.snoozle.entity.ClubEntity
class ClubMapper {
diff --git a/io/src/main/kotlin/tech/coner/trailer/io/mapper/PolicyMapper.kt b/io/src/main/kotlin/tech/coner/trailer/io/mapper/PolicyMapper.kt
index ef080410e..6a54e4bc5 100644
--- a/io/src/main/kotlin/tech/coner/trailer/io/mapper/PolicyMapper.kt
+++ b/io/src/main/kotlin/tech/coner/trailer/io/mapper/PolicyMapper.kt
@@ -28,7 +28,7 @@ class PolicyMapper(
fun toCore(snoozle: PolicyEntity): Policy {
return Policy(
id = snoozle.id,
- club = clubService.get(),
+ club = clubService.get().getOrThrow().getOrNull()!!,
name = snoozle.name,
conePenaltySeconds = snoozle.conePenaltySeconds,
paxTimeStyle = PaxTimeStyle.valueOf(snoozle.paxTimeStyle),
diff --git a/io/src/main/kotlin/tech/coner/trailer/io/service/ClubService.kt b/io/src/main/kotlin/tech/coner/trailer/io/service/ClubService.kt
index 7d7f9b52c..0f3638071 100644
--- a/io/src/main/kotlin/tech/coner/trailer/io/service/ClubService.kt
+++ b/io/src/main/kotlin/tech/coner/trailer/io/service/ClubService.kt
@@ -1,7 +1,9 @@
package tech.coner.trailer.io.service
+import arrow.core.Either
+import arrow.core.raise.either
import tech.coner.snoozle.db.entity.EntityIoException
-import tech.coner.trailer.Club
+import tech.coner.trailer.domain.entity.Club
import tech.coner.trailer.datasource.snoozle.ClubResource
import tech.coner.trailer.datasource.snoozle.entity.ClubEntity
import tech.coner.trailer.io.constraint.ClubPersistConstraints
@@ -13,16 +15,20 @@ class ClubService(
private val mapper: ClubMapper
) {
- fun get(): Club {
- return try {
- mapper.toCore(resource.read(ClubEntity.Key))
- } catch (notFoundException: EntityIoException.NotFound) {
- throw NotFoundException(message = "Club not found.", cause = notFoundException)
- } catch (readFailure: EntityIoException.ReadFailure) {
- throw ReadException(message = "Failed to read contents of Club from storage.", cause = readFailure)
+ fun get(): Result> = runCatching {
+ either {
+ try {
+ mapper.toCore(resource.read(ClubEntity.Key))
+ } catch (nFE: NotFoundException) {
+ raise(GetFailure.NotFound)
+ }
}
}
+ sealed interface GetFailure {
+ data object NotFound : GetFailure
+ }
+
fun createOrUpdate(
name: String
): Result = runCatching {
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/adapter/ClubAdapters.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/adapter/ClubAdapters.kt
deleted file mode 100644
index 51bb8ab5d..000000000
--- a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/adapter/ClubAdapters.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package tech.coner.trailer.presentation.adapter
-
-import tech.coner.trailer.Club
-import tech.coner.trailer.io.constraint.ClubPersistConstraints
-import tech.coner.trailer.presentation.model.ClubModel
-
-class ClubNameStringFieldAdapter : tech.coner.trailer.presentation.library.adapter.StringFieldAdapter {
- override operator fun invoke(model: Club): String {
- return model.name
- }
-}
-
-class ClubModelAdapter(
- val name: ClubNameStringFieldAdapter,
- private val clubPersistConstraints: ClubPersistConstraints
-) : tech.coner.trailer.presentation.library.adapter.Adapter {
- override fun invoke(model: Club): ClubModel {
- return ClubModel(
- item = model,
- constraints = clubPersistConstraints,
- adapter = this
- )
- }
-
-}
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/adapter/AdapterModule.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/adapter/AdapterModule.kt
index 1976ebc33..31734497e 100644
--- a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/adapter/AdapterModule.kt
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/adapter/AdapterModule.kt
@@ -3,6 +3,7 @@ package tech.coner.trailer.presentation.di.adapter
import org.kodein.di.*
import tech.coner.trailer.*
import tech.coner.trailer.di.DataSessionScope
+import tech.coner.trailer.domain.entity.Club
import tech.coner.trailer.io.model.PolicyCollection
import tech.coner.trailer.presentation.adapter.*
import tech.coner.trailer.presentation.adapter.eventresults.*
@@ -31,11 +32,6 @@ val presentationAdapterModule = DI.Module("tech.coner.trailer.presentation.adapt
bindSingleton { new(::ClassParentModelAdapter) }
bindSingleton> { instance() }
- // Club
- bind { scoped(DataSessionScope).singleton { new(::ClubModelAdapter) } }
- bind> { scoped(DataSessionScope).singleton { instance() } }
- bindSingleton { new(::ClubNameStringFieldAdapter) }
-
// Event
bindSingleton { new(::EventIdStringFieldAdapter) }
bindSingleton { new(::EventNameStringFieldAdapter) }
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/presenter/PresenterModule.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/presenter/PresenterModule.kt
index b5cd2650f..d4d3442e6 100644
--- a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/presenter/PresenterModule.kt
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/di/presenter/PresenterModule.kt
@@ -1,34 +1,25 @@
package tech.coner.trailer.presentation.di.presenter
-import org.kodein.di.*
-import tech.coner.trailer.Club
+import org.kodein.di.DI
+import org.kodein.di.bind
+import org.kodein.di.instance
+import org.kodein.di.multiton
+import org.kodein.di.scoped
+import org.kodein.di.singleton
import tech.coner.trailer.di.DataSessionScope
import tech.coner.trailer.presentation.di.constraint.presentationConstraintModule
-import tech.coner.trailer.presentation.library.adapter.LoadableItemAdapter
-import tech.coner.trailer.presentation.library.presenter.Presenter
-import tech.coner.trailer.presentation.library.presenter.PresenterCoroutineScope
-import tech.coner.trailer.presentation.library.state.LoadableItem
-import tech.coner.trailer.presentation.presenter.club.ClubPresenter
-import tech.coner.trailer.presentation.presenter.club.SecondDraftClubPresenter
+import tech.coner.trailer.presentation.presenter.club.ClubDetailPresenter
import tech.coner.trailer.presentation.presenter.person.PersonDetailPresenter
import tech.coner.trailer.presentation.presenter.run.EventRunLatestPresenter
-import tech.coner.trailer.presentation.state.ClubPresenterState
+import tech.coner.trailer.toolkit.presentation.presenter.PresenterCoroutineScope
val presenterModule = DI.Module("tech.coner.trailer.presentation.presenter") {
importOnce(presentationConstraintModule)
// Club
bind {
- scoped(DataSessionScope).multiton { arg: Presenter.Argument.Nothing ->
- ClubPresenter(arg, instance(), instance(), instance())
- }
- }
- bind {
- scoped(DataSessionScope).multiton { initialState: ClubPresenterState ->
- SecondDraftClubPresenter(
- initialState = initialState,
- adapter = tech.coner.trailer.presentation.library.adapter.LoadableItemAdapter(instance())
- )
+ scoped(DataSessionScope).singleton {
+ ClubDetailPresenter()
}
}
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/ClubModel.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/ClubModel.kt
deleted file mode 100644
index db0dac4c7..000000000
--- a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/ClubModel.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package tech.coner.trailer.presentation.model
-
-import tech.coner.trailer.Club
-import tech.coner.trailer.io.constraint.ClubPersistConstraints
-import tech.coner.trailer.presentation.adapter.ClubModelAdapter
-import tech.coner.trailer.presentation.library.model.BaseItemModel
-
-class ClubModel(
- override val initialItem: Club,
- override val constraints: ClubPersistConstraints,
- private val adapter: ClubModelAdapter
-) : BaseItemModel() {
-
- val nameValidated = validatedPropertyFlow(Club::name) { adapter.name(it) }
- var name
- get() = adapter.name(pendingItem)
- set(value) = mutatePendingItem { it.copy(name = value) }
-}
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailItemModel.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailItemModel.kt
new file mode 100644
index 000000000..6291f5069
--- /dev/null
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailItemModel.kt
@@ -0,0 +1,21 @@
+package tech.coner.trailer.presentation.model.club
+
+import tech.coner.trailer.domain.validation.ClubValidator
+import tech.coner.trailer.toolkit.presentation.model.BaseItemModel
+import tech.coner.trailer.toolkit.validation.Validator
+
+class ClubDetailItemModel(
+ override val initialItem: ClubDetailModel,
+ private val adapter: ClubEntityModelAdapter = ClubEntityModelAdapter()
+) : BaseItemModel() {
+
+ override val validator: Validator = Validator {
+ input(
+ otherTypeValidator = ClubValidator(),
+ mapContextFn = {},
+ mapInputFn = { adapter.modelToEntityAdapter(it) },
+ mapFeedbackObjectFn = { ClubDetailModelFeedback(it) }
+ )
+ }
+ override val validatorContext = Unit
+}
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailModel.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailModel.kt
new file mode 100644
index 000000000..153d955e0
--- /dev/null
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailModel.kt
@@ -0,0 +1,7 @@
+package tech.coner.trailer.presentation.model.club
+
+import tech.coner.trailer.toolkit.presentation.model.Model
+
+data class ClubDetailModel(
+ val name: String
+) : Model
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailModelFeedback.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailModelFeedback.kt
new file mode 100644
index 000000000..dd1372e8c
--- /dev/null
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubDetailModelFeedback.kt
@@ -0,0 +1,16 @@
+package tech.coner.trailer.presentation.model.club
+
+import tech.coner.trailer.domain.entity.Club
+import tech.coner.trailer.domain.validation.ClubFeedback
+import tech.coner.trailer.toolkit.validation.Feedback
+import tech.coner.trailer.toolkit.validation.FeedbackDelegate
+import tech.coner.trailer.toolkit.validation.adapter.propertyAdapterOf
+
+data class ClubDetailModelFeedback(
+ val source: ClubFeedback
+) : Feedback by FeedbackDelegate(
+ feedback = source,
+ propertyAdapter = propertyAdapterOf(
+ Club::name to ClubDetailModel::name
+ )
+)
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubEntityModelAdapter.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubEntityModelAdapter.kt
new file mode 100644
index 000000000..834497536
--- /dev/null
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/model/club/ClubEntityModelAdapter.kt
@@ -0,0 +1,17 @@
+package tech.coner.trailer.presentation.model.club
+
+import tech.coner.trailer.domain.entity.Club
+import tech.coner.trailer.toolkit.presentation.adapter.EntityModelAdapter
+
+class ClubEntityModelAdapter : EntityModelAdapter() {
+ override val entityToModelAdapter: (Club) -> ClubDetailModel = {
+ ClubDetailModel(
+ name = it.name
+ )
+ }
+ override val modelToEntityAdapter: (ClubDetailModel) -> Club = {
+ Club(
+ name = it.name
+ )
+ }
+}
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/ClubDetailPresenter.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/ClubDetailPresenter.kt
new file mode 100644
index 000000000..ef6fc0dff
--- /dev/null
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/ClubDetailPresenter.kt
@@ -0,0 +1,80 @@
+package tech.coner.trailer.presentation.presenter.club
+
+import arrow.core.Either
+import arrow.core.raise.either
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.StateFlow
+import tech.coner.trailer.io.service.ClubService
+import tech.coner.trailer.io.util.runSuspendCatching
+import tech.coner.trailer.presentation.model.club.ClubDetailItemModel
+import tech.coner.trailer.presentation.model.club.ClubDetailModel
+import tech.coner.trailer.presentation.model.club.ClubEntityModelAdapter
+import tech.coner.trailer.presentation.state.club.ClubDetailState
+import tech.coner.trailer.toolkit.presentation.model.Loadable
+import tech.coner.trailer.toolkit.presentation.model.whenLoadedSuccess
+import tech.coner.trailer.toolkit.presentation.presenter.ItemModelPresenter
+import tech.coner.trailer.toolkit.presentation.presenter.LoadablePresenter
+import tech.coner.trailer.toolkit.presentation.presenter.PresenterCoroutineScope
+import tech.coner.trailer.toolkit.presentation.presenter.StatefulPresenter
+import tech.coner.trailer.toolkit.presentation.state.StateContainer
+import tech.coner.trailer.toolkit.presentation.state.mutableLoadedProperty
+
+class ClubDetailPresenter(
+ initialState: ClubDetailState = ClubDetailState(loadable = Loadable.Empty()),
+ private val adapter: ClubEntityModelAdapter,
+ private val service: ClubService,
+ coroutineScope: PresenterCoroutineScope
+) : LoadablePresenter,
+ StatefulPresenter,
+ ItemModelPresenter,
+ CoroutineScope by coroutineScope {
+
+ private val stateContainer = StateContainer(initialState)
+ override val state: ClubDetailState get() = stateContainer.state
+ override val stateFlow: StateFlow get() = stateContainer.stateFlow
+
+ override suspend fun load(): Deferred>> = coroutineScope {
+ async {
+ runSuspendCatching {
+ stateContainer.update { it.copy(loadable = Loadable.Loading()) }
+ either {
+ service.get().getOrThrow()
+ .map { club ->
+ ClubDetailItemModel(
+ initialItem = adapter.entityToModelAdapter(club),
+ adapter = adapter
+ )
+ }
+ .onLeft { failure -> stateContainer.update { it.copy(loadable = Loadable.Loaded(Either.Left(failure))) } }
+ .bind()
+
+ }
+ }
+ .onFailure { throwable ->
+ stateContainer.update { it.copy(loadable = Loadable.FailedExceptionally(throwable)) }
+ }
+ }
+ }
+
+
+ override suspend fun commit() {
+ state.loadable.whenLoadedSuccess { it.commit() }
+ }
+
+ override suspend fun validate() {
+ state.loadable.whenLoadedSuccess { it.validate() }
+ }
+
+ override suspend fun reset() {
+ state.loadable.whenLoadedSuccess { it.reset() }
+ }
+
+ val name = stateContainer.mutableLoadedProperty(
+ getFn = { name },
+ updateFn = { copy(name = it) },
+ property = ClubDetailModel::name
+ )
+}
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/ClubPresenter.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/ClubPresenter.kt
deleted file mode 100644
index 9375f1408..000000000
--- a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/ClubPresenter.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package tech.coner.trailer.presentation.presenter.club
-
-import kotlinx.coroutines.CoroutineScope
-import tech.coner.trailer.Club
-import tech.coner.trailer.io.service.ClubService
-import tech.coner.trailer.io.util.runSuspendCatching
-import tech.coner.trailer.presentation.adapter.ClubModelAdapter
-import tech.coner.trailer.presentation.model.ClubModel
-import tech.coner.trailer.presentation.library.presenter.BaseItemPresenter
-import tech.coner.trailer.presentation.library.presenter.Presenter
-import tech.coner.trailer.presentation.library.presenter.PresenterCoroutineScope
-
-class ClubPresenter(
- override val argument: Presenter.Argument.Nothing,
- coroutineScope: PresenterCoroutineScope,
- private val service: ClubService,
- override val adapter: ClubModelAdapter
-) : BaseItemPresenter(),
- CoroutineScope by coroutineScope {
-
- override val entityDefault = Club("")
-
- override suspend fun performLoad(): Result = runSuspendCatching {
- service.get()
- }
-
- suspend fun createOrUpdate() = runSuspendCatching {
- service.createOrUpdate(name = itemModel.pendingItem.name).getOrThrow()
- }
-}
-
-typealias ClubPresenterFactory = (Presenter.Argument.Nothing) -> ClubPresenter
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/SecondDraftClubPresenter.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/SecondDraftClubPresenter.kt
deleted file mode 100644
index b80ce05d6..000000000
--- a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/presenter/club/SecondDraftClubPresenter.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package tech.coner.trailer.presentation.presenter.club
-
-import tech.coner.trailer.Club
-import tech.coner.trailer.presentation.library.adapter.LoadableItemAdapter
-import tech.coner.trailer.presentation.library.presenter.LoadableItemPresenter
-import tech.coner.trailer.presentation.model.ClubModel
-import tech.coner.trailer.presentation.state.ClubPresenterState
-
-class SecondDraftClubPresenter(
- override val initialState: ClubPresenterState,
- override val adapter: tech.coner.trailer.presentation.library.adapter.LoadableItemAdapter
-) : LoadableItemPresenter() {
-}
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/state/ClubPresenterState.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/state/ClubPresenterState.kt
deleted file mode 100644
index 60af7cc5c..000000000
--- a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/state/ClubPresenterState.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package tech.coner.trailer.presentation.state
-
-import tech.coner.trailer.Club
-import tech.coner.trailer.presentation.library.state.LoadableItem
-import tech.coner.trailer.presentation.library.state.LoadableItemState
-
-data class ClubPresenterState(
- override val loadable: LoadableItem
-) : LoadableItemState {
-}
\ No newline at end of file
diff --git a/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/state/club/ClubDetailState.kt b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/state/club/ClubDetailState.kt
new file mode 100644
index 000000000..dc2f664b4
--- /dev/null
+++ b/presentation/presentation/src/main/kotlin/tech/coner/trailer/presentation/state/club/ClubDetailState.kt
@@ -0,0 +1,12 @@
+package tech.coner.trailer.presentation.state.club
+
+import tech.coner.trailer.io.service.ClubService
+import tech.coner.trailer.presentation.model.club.ClubDetailItemModel
+import tech.coner.trailer.presentation.model.club.ClubDetailModel
+import tech.coner.trailer.presentation.model.club.ClubDetailModelFeedback
+import tech.coner.trailer.toolkit.presentation.model.Loadable
+import tech.coner.trailer.toolkit.presentation.state.LoadableState
+
+data class ClubDetailState(
+ override val loadable: Loadable = Loadable.Empty()
+) : LoadableState
diff --git a/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/presenter/BasePresenter.kt b/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/presenter/BasePresenter.kt
deleted file mode 100644
index b7a01d039..000000000
--- a/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/presenter/BasePresenter.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package tech.coner.trailer.toolkit.presentation.presenter
-
-abstract class BasePresenter : Presenter {
-
- protected abstract val argument: ARGUMENT
-}
\ No newline at end of file
diff --git a/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/presenter/Presenter.kt b/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/presenter/Presenter.kt
deleted file mode 100644
index 6baae6303..000000000
--- a/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/presenter/Presenter.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package tech.coner.trailer.toolkit.presentation.presenter
-
-@Deprecated("First draft presenter to be replaced with second draft presenter (naming TBD)")
-interface Presenter {
-
- interface Argument {
- object Nothing : Argument {
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
- return true
- }
-
- override fun hashCode(): Int {
- return javaClass.hashCode()
- }
- }
- }
-
-
-}
diff --git a/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/state/LoadableState.kt b/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/state/LoadableState.kt
index 050e370b1..74965489f 100644
--- a/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/state/LoadableState.kt
+++ b/toolkit/presentation/presentation/src/main/kotlin/tech/coner/trailer/toolkit/presentation/state/LoadableState.kt
@@ -1,14 +1,17 @@
package tech.coner.trailer.toolkit.presentation.state
-import kotlinx.coroutines.flow.*
+import kotlin.reflect.KProperty1
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import tech.coner.trailer.toolkit.presentation.model.ItemModel
import tech.coner.trailer.toolkit.presentation.model.Loadable
import tech.coner.trailer.toolkit.presentation.model.letLoadedSuccess
import tech.coner.trailer.toolkit.presentation.model.whenLoadedSuccess
import tech.coner.trailer.toolkit.validation.Feedback
-import kotlin.reflect.KProperty1
-interface LoadableState, FEEDBACK : Feedback- >: State {
+interface LoadableState, FEEDBACK : Feedback
- > : State {
val loadable: Loadable
}
diff --git a/toolkit/samples/fooapp/fooapp-common/src/main/kotlin/tech/coner/trailer/toolkit/sample/fooapp/domain/validation/FooFeedback.kt b/toolkit/samples/fooapp/fooapp-common/src/main/kotlin/tech/coner/trailer/toolkit/sample/fooapp/domain/validation/FooFeedback.kt
index b515b1bb5..a01b2abe6 100644
--- a/toolkit/samples/fooapp/fooapp-common/src/main/kotlin/tech/coner/trailer/toolkit/sample/fooapp/domain/validation/FooFeedback.kt
+++ b/toolkit/samples/fooapp/fooapp-common/src/main/kotlin/tech/coner/trailer/toolkit/sample/fooapp/domain/validation/FooFeedback.kt
@@ -3,7 +3,6 @@ package tech.coner.trailer.toolkit.sample.fooapp.domain.validation
import tech.coner.trailer.toolkit.sample.fooapp.domain.entity.Foo
import tech.coner.trailer.toolkit.validation.Feedback
import tech.coner.trailer.toolkit.validation.Severity
-import kotlin.reflect.KProperty1
sealed class FooFeedback : Feedback {