Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#6] 공고 삭제 기능 구현 #13

Merged
merged 8 commits into from
Nov 10, 2024
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:withu_app/core/core.dart';
import 'package:withu_app/feature/job_posting/data/data.dart';
import 'package:withu_app/shared/data/data.dart';

class JobPostingMockApi extends JobPostingApi with MockAPI {
/// 공고 목록
Expand Down Expand Up @@ -144,4 +145,28 @@ class JobPostingMockApi extends JobPostingApi with MockAPI {
return const ApiResponse.error();
}
}

/// 공고 삭제
@override
FutureOr<ApiResponse<DeleteResponseDto>> deleteJobPosting({
required String jobPostingId,
}) async {
try {
dioAdapter.onDelete(
url,
(server) => server.reply(
200,
DeleteResponseDto.mockSuccess(id: jobPostingId).toJson(),
delay: const Duration(milliseconds: 1000),
),
);

final response = await dio.delete(url);
return ApiResponse.success(
DeleteResponseDto.fromJson(response.data),
);
} catch (e) {
return const ApiResponse.error();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:withu_app/core/core.dart';
import 'package:withu_app/feature/job_posting/data/data.dart';
import 'package:withu_app/shared/data/data.dart';

abstract class JobPostingApi extends API {
/// 공고 목록
Expand All @@ -23,4 +24,9 @@ abstract class JobPostingApi extends API {
FutureOr<ApiResponse<JobPostingDetailDto>> closeJobPosting({
required String jobPostingId,
});

/// 공고 삭제
FutureOr<ApiResponse<DeleteResponseDto>> deleteJobPosting({
required String jobPostingId,
});
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:withu_app/core/core.dart';
import 'package:withu_app/feature/job_posting/data/data.dart';
import 'package:withu_app/shared/data/data.dart';

class JobPostingApiImpl extends JobPostingApi {
/// 공고 목록
Expand Down Expand Up @@ -35,4 +36,12 @@ class JobPostingApiImpl extends JobPostingApi {
}) {
return const ApiResponse.error();
}

/// 공고 삭제
@override
FutureOr<ApiResponse<DeleteResponseDto>> deleteJobPosting({
required String jobPostingId,
}) {
return const ApiResponse.error();
}
}
11 changes: 10 additions & 1 deletion lib/feature/job_posting/data/repositories/repository_impl.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:withu_app/core/core.dart';
import 'package:withu_app/feature/job_posting/data/data.dart';
import 'package:withu_app/feature/job_posting/domain/domain.dart';
import 'package:withu_app/shared/data/data.dart';

class JobPostingRepositoryImpl implements JobPostingRepository {
final JobPostingApi api;
Expand Down Expand Up @@ -39,11 +40,19 @@ class JobPostingRepositoryImpl implements JobPostingRepository {
return await api.getJobPosting(jobPostingId: jobPostingId);
}

/// 공고 상세 조회
/// 공고 마감
@override
Future<ApiResponse<JobPostingDetailDto>> closeJobPosting({
required String jobPostingId,
}) async {
return await api.closeJobPosting(jobPostingId: jobPostingId);
}

/// 공고 삭제
@override
Future<ApiResponse<DeleteResponseDto>> deleteJobPosting({
required String jobPostingId,
}) async {
return await api.deleteJobPosting(jobPostingId: jobPostingId);
}
}
6 changes: 6 additions & 0 deletions lib/feature/job_posting/domain/repositories/repositories.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:withu_app/core/core.dart';
import 'package:withu_app/feature/job_posting/data/data.dart';
import 'package:withu_app/shared/data/data.dart';

abstract class JobPostingRepository {
/// 공고 목록 조회
Expand All @@ -22,4 +23,9 @@ abstract class JobPostingRepository {
Future<ApiResponse<JobPostingDetailDto>> closeJobPosting({
required String jobPostingId,
});

/// 공고 삭제
Future<ApiResponse<DeleteResponseDto>> deleteJobPosting({
required String jobPostingId,
});
}
6 changes: 6 additions & 0 deletions lib/feature/job_posting/domain/usecases/usecases.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:withu_app/core/core.dart';
import 'package:withu_app/feature/job_posting/data/data.dart';
import 'package:withu_app/feature/job_posting/domain/domain.dart';
import 'package:withu_app/feature/job_posting/domain/entities/job_posting_detail_entity.dart';
import 'package:withu_app/shared/data/data.dart';

part 'usecases_impl.dart';

Expand All @@ -24,4 +25,9 @@ abstract class JobPostingUseCase {
Future<Either<JobPostingDetailEntity>> closeJobPosting({
required String jobPostingId,
});

/// 공고 삭제
Future<Either<bool>> deleteJobPosting({
required String jobPostingId,
});
}
20 changes: 20 additions & 0 deletions lib/feature/job_posting/domain/usecases/usecases_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ class JobPostingUseCaseImpl implements JobPostingUseCase {
},
);
}

/// 공고 삭제
@override
Future<Either<bool>> deleteJobPosting({
required String jobPostingId,
}) async {
final result =
await repository.deleteJobPosting(jobPostingId: jobPostingId);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await repository.deleteJobPosting(jobPostingId: jobPostingId);
await repository.delete(id: jobPostingId);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#11 PR 수정하면서 같이 반영해 푸시했습니다!
jobPostingRepo.delete()로 사용할 수 있게 변경했습니다!


return result.maybeWhen(
success: (DeleteResponseDto dto) {
return dto.deleted
? const Either.success(true)
: Either.fail(dto.message ?? '');
},
orElse: () {
return Either.fail(StringRes.serverError.tr);
},
);
}
}

extension on JobPostingUseCase {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class JobPostingDetailBloc
on<ClearMessage>(_clearMessage);
on<OnGettingDetailData>(_onGettingDetailData);
on<OnClosedJobPosting>(_onClosedJobPosting);
on<OnDeletedJobPosting>(_onDeletedJobPosting);
}

/// 메시지 초기화 이벤트.
Expand Down Expand Up @@ -75,16 +76,59 @@ class JobPostingDetailBloc
jobPostingId: jobPostingId,
);

result.when(success: (JobPostingDetailEntity data) {
emit(state.copyWith(
status: JobPostingDetailStatus.closed,
));
}, fail: (String message) {
emit(state.copyWith(
status: JobPostingDetailStatus.fail,
entity: null,
message: message,
));
});
result.when(
success: (JobPostingDetailEntity data) {
emit(
state.copyWith(
status: JobPostingDetailStatus.closed,
),
);
},
fail: (String message) {
emit(
state.copyWith(
status: JobPostingDetailStatus.fail,
entity: null,
message: message,
),
);
},
);
}

/// 공고 삭제
void _onDeletedJobPosting(
OnDeletedJobPosting event,
Emitter<JobPostingDetailState> emit,
) async {
final String? jobPostingId = state.entity?.id;

if (jobPostingId == null) {
return;
}

emit(state.copyWith(status: JobPostingDetailStatus.loading));

final Either<bool> result = await useCase.deleteJobPosting(
jobPostingId: jobPostingId,
);

result.when(
success: (bool data) {
emit(
state.copyWith(
status: JobPostingDetailStatus.deleted,
),
);
},
fail: (String message) {
emit(
state.copyWith(
status: JobPostingDetailStatus.fail,
message: message,
),
);
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ class ClearMessage extends JobPostingDetailEvent {}

/// 공고 마감
class OnClosedJobPosting extends JobPostingDetailEvent {}

/// 공고 삭제
class OnDeletedJobPosting extends JobPostingDetailEvent {}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ part of 'job_posting_detail_bloc.dart';
/// loading: Api 통신 중
/// success: API 통신 성공
/// fail: API 통신 실패
/// closed: 마감 상태로 변경됨
enum JobPostingDetailStatus { initial, loading, success, fail, closed }
/// closed: 마감 상태
/// deleted: 삭제 상태
enum JobPostingDetailStatus { initial, loading, success, fail, closed, deleted }

extension JobPostingDetailStatusExt on JobPostingDetailStatus {
bool get isInitial => this == JobPostingDetailStatus.initial;
Expand All @@ -15,6 +16,8 @@ extension JobPostingDetailStatusExt on JobPostingDetailStatus {
bool get isSuccess => this == JobPostingDetailStatus.success;

bool get isClosed => this == JobPostingDetailStatus.closed;

bool get isDeleted => this == JobPostingDetailStatus.deleted;
}

@freezed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ class _JobPostingDetailPage extends StatelessWidget {
CustomAlertDialog.showContentAlert(
context: context,
content: state.message,
closeCallback: () {},
closeCallback: () {
context.read<JobPostingDetailBloc>().add(ClearMessage());
},
);
}

// 마감으로 변경되었을 때
if (state.status.isClosed) {
context.router.back();
if (state.status.isClosed || state.status.isDeleted) {
context.router.maybePop(true);
}
},
builder: (context, state) {
Expand Down Expand Up @@ -158,7 +160,7 @@ class _AppBar extends StatelessWidget {
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
context.back();
context.router.back();
},
),
actions: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,14 @@ class JobPostingsListState<B extends JobPostingsBloc>
builderDelegate: PagedChildBuilderDelegate<JobPostingEntity>(
itemBuilder: (context, item, index) => JobPostingsItem(
entity: item,
onPressed: () {
context.router.push(
onPressed: () async {
final bool? result = await context.router.push<bool>(
JobPostingDetailRoute(jobPostingId: item.id),
);

if(result == true) {
// TODO: 리프레시 추가.
}
}),
firstPageProgressIndicatorBuilder: (context) => _emptyView(),
noItemsFoundIndicatorBuilder: (context) => _emptyView(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:withu_app/core/core.dart';
import 'package:withu_app/feature/feature.dart';
import 'package:withu_app/feature/job_posting/presentation/widgets/detail_bottom_sheet/detail_bottom_sheet_type.dart';
import 'package:withu_app/shared/bottom_sheet/bottom_sheet.dart';

/// 공고 상세보기 바텀 시트 Factory
Expand Down Expand Up @@ -41,7 +40,11 @@ class _DeleteBottomSheet implements DescriptionBottomSheetOption {
String get description => StringRes.canRevertFromPostingManagement.tr;

@override
Function(Bloc? bloc) get exec => (Bloc? bloc) {};
Function(Bloc? bloc) get exec => (Bloc? bloc) {
if (bloc is JobPostingDetailBloc) {
bloc.add(OnDeletedJobPosting());
}
};
}

/// 공고 마감
Expand Down
1 change: 1 addition & 0 deletions lib/shared/data/data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'data_sources/data_sources.dart';
1 change: 1 addition & 0 deletions lib/shared/data/data_sources/data_sources.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'delete/delete_response_dto.dart';
28 changes: 28 additions & 0 deletions lib/shared/data/data_sources/delete/delete_response_dto.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:freezed_annotation/freezed_annotation.dart';

part 'delete_response_dto.freezed.dart';

part 'delete_response_dto.g.dart';

part 'delete_response_dto.mock.dart';

/// 삭제 응답 DTO
@freezed
class DeleteResponseDto with _$DeleteResponseDto {
const factory DeleteResponseDto({
required String id,
required bool deleted,
required String? message,
}) = _DeleteResponseDto;

factory DeleteResponseDto.fromJson(Map<String, Object?> json) =>
_$DeleteResponseDtoFromJson(json);

/// Mock 삭제 성공
factory DeleteResponseDto.mockSuccess({required String id}) =>
DeleteResponseDtoMock.mockSuccess(id: id);

/// Mock 삭제 실패
factory DeleteResponseDto.mockFail({required String id}) =>
DeleteResponseDtoMock.mockFail(id: id);
}
Loading
Loading