<!-- 샘플 게시판 CRUD 페이지 템플릿이다. -->
<template>
  <!-- 페이지 전체 래퍼이다. -->
  <div class="ui--content-wrapper">
    <!-- 공통 브레드크럼을 출력한다. -->
    <sdl-breadcrumb></sdl-breadcrumb>
    <!-- 목록 헤더 영역이다. -->
    <div class="ui--list-heading clearfix">
      <!-- 전체 건수를 출력한다. -->
      <span class="ui--text-total"><strong>Total</strong> {{ $filters.numberFormat(boardList.length) }}</span>
      <!-- 우측 버튼 영역이다. -->
      <div class="float-end">
        <!-- 신규 등록 폼으로 초기화한다. -->
        <button type="button" class="btn btn-primary btn-sm" @click="resetForm()">새 글</button>
      </div>
    </div>
    <!-- 목록과 입력 폼을 2단으로 배치한다. -->
    <div class="row">
      <!-- 좌측 목록 영역이다. -->
      <div class="col-6">
        <!-- 게시글 목록 테이블이다. -->
        <table class="table table-bordered ui--table">
          <!-- 컬럼 폭 정의이다. -->
          <colgroup>
            <!-- 번호 컬럼 폭이다. -->
            <col style="width: 12%" />
            <!-- 제목 컬럼 폭이다. -->
            <col style="width: 40%" />
            <!-- 작성자 컬럼 폭이다. -->
            <col style="width: 20%" />
            <!-- 등록일 컬럼 폭이다. -->
            <col style="width: 28%" />
          </colgroup>
          <!-- 테이블 헤더이다. -->
          <thead>
            <!-- 헤더 행이다. -->
            <tr>
              <!-- 번호 헤더이다. -->
              <th scope="col">번호</th>
              <!-- 제목 헤더이다. -->
              <th scope="col">제목</th>
              <!-- 작성자 헤더이다. -->
              <th scope="col">작성자</th>
              <!-- 등록일 헤더이다. -->
              <th scope="col">등록일</th>
            </tr>
          </thead>
          <!-- 테이블 본문이다. -->
          <tbody>
            <!-- 데이터가 없을 때 안내 행을 출력한다. -->
            <tr v-if="boardList.length === 0">
              <!-- 빈 목록 안내 셀이다. -->
              <td colspan="4" class="text-center">등록된 게시글이 없습니다.</td>
            </tr>
            <!-- 게시글 목록을 반복 출력한다. -->
            <tr v-for="board in boardList" :key="board.id" :class="{ 'table-primary': board.id === form.id }">
              <!-- 게시글 번호를 출력한다. -->
              <td class="text-center">{{ board.id }}</td>
              <!-- 제목을 클릭하면 상세를 조회한다. -->
              <td>
                <!-- 상세 조회 버튼처럼 동작하는 링크이다. -->
                <a href="javascript:void(0);" @click="selectBoard(board.id)">{{ board.title }}</a>
              </td>
              <!-- 작성자를 출력한다. -->
              <td class="text-center">{{ board.author }}</td>
              <!-- 등록일을 출력한다. -->
              <td class="text-center">{{ formatDate(board.createdAt) }}</td>
            </tr>
          </tbody>
        </table>
      </div>
      <!-- 우측 입력 폼 영역이다. -->
      <div class="col-6">
        <!-- 입력 폼 컨테이너이다. -->
        <div class="ui--form-container">
          <!-- 폼 제목을 출력한다. -->
          <h4 class="mb-3">Sample Board {{ mode === 'CREATE' ? '등록' : '수정' }}</h4>
          <!-- 번호와 등록일을 표시한다. -->
          <div class="row">
            <!-- 번호 영역이다. -->
            <div class="col-6 mb-3">
              <!-- 번호 라벨이다. -->
              <label>번호</label>
              <!-- 번호 입력창이다. -->
              <input :value="form.id || ''" type="text" class="form-control" readonly />
            </div>
            <!-- 등록일 영역이다. -->
            <div class="col-6 mb-3">
              <!-- 등록일 라벨이다. -->
              <label>등록일</label>
              <!-- 등록일 입력창이다. -->
              <input :value="formatDate(form.createdAt)" type="text" class="form-control" readonly />
            </div>
          </div>
          <!-- 제목 입력 영역이다. -->
          <div class="mb-3">
            <!-- 제목 라벨이다. -->
            <label>제목 <span class="ui--text-required">&#42;</span></label>
            <!-- 제목 입력창이다. -->
            <input v-model.trim="form.title" type="text" class="form-control" maxlength="200" />
          </div>
          <!-- 작성자 입력 영역이다. -->
          <div class="mb-3">
            <!-- 작성자 라벨이다. -->
            <label>작성자 <span class="ui--text-required">&#42;</span></label>
            <!-- 작성자 입력창이다. -->
            <input v-model.trim="form.author" type="text" class="form-control" maxlength="100" />
          </div>
          <!-- 내용 입력 영역이다. -->
          <div class="mb-3">
            <!-- 내용 라벨이다. -->
            <label>내용 <span class="ui--text-required">&#42;</span></label>
            <!-- 내용 입력창이다. -->
            <textarea v-model.trim="form.content" class="form-control" rows="10"></textarea>
          </div>
          <!-- 버튼 영역이다. -->
          <div class="ui--button-container">
            <!-- 입력 폼을 초기화한다. -->
            <button type="button" class="btn btn-secondary btn-lg" @click="resetForm()">초기화</button>
            <!-- 현재 입력값을 저장한다. -->
            <button type="button" class="btn btn-primary btn-lg" @click="saveBoard()">저장</button>
            <!-- 수정 모드일 때만 삭제 버튼을 노출한다. -->
            <button v-if="mode === 'EDIT'" type="button" class="btn btn-danger btn-lg" @click="confirmDelete(form.id)">삭제</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<!-- 샘플 게시판 CRUD 페이지 스크립트이다. -->
<script>
// HTTP 통신을 위해 axios를 사용한다.
import axios from 'axios';
// 공통 유틸을 사용한다.
import SDLUtil from '@/utils/SDLUtil';

// 샘플 게시판 CRUD 컴포넌트를 정의한다.
export default {
  // 컴포넌트 이름을 정의한다.
  name: 'PgBoardPage',
  // 화면 상태를 정의한다.
  data() {
    // 초기 상태를 반환한다.
    return {
      // 게시글 목록 상태이다.
      boardList: [],
      // 현재 폼 모드 상태이다.
      mode: 'CREATE',
      // 입력 폼 상태이다.
      form: {
        id: null,
        title: '',
        content: '',
        author: '',
        createdAt: null,
      },
    };
  },
  // 화면 동작 메서드를 정의한다.
  methods: {
    // 빈 입력 폼 객체를 생성한다.
    createEmptyForm() {
      // 신규 등록용 기본값을 반환한다.
      return {
        // 게시글 번호 기본값이다.
        id: null,
        // 제목 기본값이다.
        title: '',
        // 내용 기본값이다.
        content: '',
        // 작성자 기본값이다.
        author: '',
        // 등록일 기본값이다.
        createdAt: null,
      };
    },
    // 페이지 초기화 메서드이다.
    init() {
      // 목록을 먼저 조회한다.
      this.fetchBoardList();
    },
    // 게시글 목록을 조회한다.
    async fetchBoardList() {
      // 로딩 바를 표시한다.
      SDLUtil.showLoadingBar(true);
      try {
        // 목록 조회 API를 호출한다.
        const { data } = await axios.get(`${SDLUtil.API_URL}/pg-board/samples`);
        // 조회 결과를 목록 상태에 저장한다.
        this.boardList = data || [];
      } catch (err) {
        // 오류가 발생하면 공통 에러 알림을 출력한다.
        SDLUtil.errorAlert(err);
      } finally {
        // 로딩 바를 종료한다.
        SDLUtil.showLoadingBar(false);
      }
    },
    // 게시글 상세를 조회한다.
    async selectBoard(id) {
      // 로딩 바를 표시한다.
      SDLUtil.showLoadingBar(true);
      try {
        // 상세 조회 API를 호출한다.
        const { data } = await axios.get(`${SDLUtil.API_URL}/pg-board/samples/${id}`);
        // 조회한 데이터를 폼에 반영한다.
        this.form = {
          // 게시글 번호를 반영한다.
          id: data.id,
          // 제목을 반영한다.
          title: data.title,
          // 내용을 반영한다.
          content: data.content,
          // 작성자를 반영한다.
          author: data.author,
          // 등록일을 반영한다.
          createdAt: data.createdAt,
        };
        // 수정 모드로 전환한다.
        this.mode = 'EDIT';
      } catch (err) {
        // 오류가 발생하면 공통 에러 알림을 출력한다.
        SDLUtil.errorAlert(err);
      } finally {
        // 로딩 바를 종료한다.
        SDLUtil.showLoadingBar(false);
      }
    },
    // 입력 폼을 신규 등록 상태로 초기화한다.
    resetForm() {
      // 모드를 등록으로 변경한다.
      this.mode = 'CREATE';
      // 폼 값을 초기화한다.
      this.form = this.createEmptyForm();
    },
    // 입력값 유효성을 검증한다.
    validateForm() {
      // 제목 입력 여부를 검증한다.
      if (!this.form.title) {
        // 제목 누락 알림을 출력한다.
        SDLUtil.alert('제목을 입력하세요.');
        // 검증 실패를 반환한다.
        return false;
      }
      // 작성자 입력 여부를 검증한다.
      if (!this.form.author) {
        // 작성자 누락 알림을 출력한다.
        SDLUtil.alert('작성자를 입력하세요.');
        // 검증 실패를 반환한다.
        return false;
      }
      // 내용 입력 여부를 검증한다.
      if (!this.form.content) {
        // 내용 누락 알림을 출력한다.
        SDLUtil.alert('내용을 입력하세요.');
        // 검증 실패를 반환한다.
        return false;
      }
      // 모든 검증을 통과했음을 반환한다.
      return true;
    },
    // 현재 폼 데이터를 저장한다.
    async saveBoard() {
      // 저장 전 유효성을 검증한다.
      if (!this.validateForm()) {
        // 검증 실패 시 저장을 중단한다.
        return;
      }
      // 서버로 전송할 payload를 구성한다.
      const payload = {
        // 제목을 전송한다.
        title: this.form.title,
        // 내용을 전송한다.
        content: this.form.content,
        // 작성자를 전송한다.
        author: this.form.author,
      };
      // 로딩 바를 표시한다.
      SDLUtil.showLoadingBar(true);
      try {
        // 저장 결과를 담을 변수를 선언한다.
        let savedData = null;
        // 수정 모드 여부를 확인한다.
        if (this.mode === 'EDIT' && this.form.id) {
          // 수정 API를 호출한다.
          const { data } = await axios.put(`${SDLUtil.API_URL}/pg-board/samples/${this.form.id}`, payload);
          // 수정 결과를 저장한다.
          savedData = data;
        } else {
          // 등록 API를 호출한다.
          const { data } = await axios.post(`${SDLUtil.API_URL}/pg-board/samples`, payload);
          // 등록 결과를 저장한다.
          savedData = data;
        }
        // 저장 후 목록을 새로 조회한다.
        await this.fetchBoardList();
        // 저장된 게시글이 있으면 상세를 다시 로드한다.
        if (savedData && savedData.id) {
          // 저장된 게시글 상세를 선택한다.
          await this.selectBoard(savedData.id);
        }
        // 저장 완료 알림을 출력한다.
        SDLUtil.alert('저장되었습니다.');
      } catch (err) {
        // 오류가 발생하면 공통 에러 알림을 출력한다.
        SDLUtil.errorAlert(err);
      } finally {
        // 로딩 바를 종료한다.
        SDLUtil.showLoadingBar(false);
      }
    },
    // 삭제 전 사용자 확인을 수행한다.
    confirmDelete(id) {
      // 삭제 대상이 없으면 즉시 종료한다.
      if (!id) {
        // 함수 실행을 종료한다.
        return;
      }
      // 공통 확인 팝업을 출력한다.
      SDLUtil.confirm({
        // 확인 메시지를 설정한다.
        msg: '삭제하시겠습니까?',
        // 확인 버튼 이벤트를 설정한다.
        onOkEvt: () => {
          // 실제 삭제를 수행한다.
          this.deleteBoard(id);
        },
      });
    },
    // 게시글을 삭제한다.
    async deleteBoard(id) {
      // 로딩 바를 표시한다.
      SDLUtil.showLoadingBar(true);
      try {
        // 삭제 API를 호출한다.
        await axios.delete(`${SDLUtil.API_URL}/pg-board/samples/${id}`);
        // 삭제 후 목록을 새로 조회한다.
        await this.fetchBoardList();
        // 삭제 후 폼을 초기화한다.
        this.resetForm();
        // 삭제 완료 알림을 출력한다.
        SDLUtil.alert('삭제되었습니다.');
      } catch (err) {
        // 오류가 발생하면 공통 에러 알림을 출력한다.
        SDLUtil.errorAlert(err);
      } finally {
        // 로딩 바를 종료한다.
        SDLUtil.showLoadingBar(false);
      }
    },
    // 등록일 표시 형식을 변환한다.
    formatDate(value) {
      // 값이 없으면 빈 문자열을 반환한다.
      if (!value) {
        // 빈 문자열을 반환한다.
        return '';
      }
      // 공통 날짜 포맷 필터를 사용해 문자열을 반환한다.
      return this.$filters.dateFormat(value);
    },
  },
  // 컴포넌트 마운트 후 초기화를 수행한다.
  mounted() {
    // 다음 렌더 사이클에서 초기화를 호출한다.
    this.$nextTick(() => {
      // 화면 초기화를 실행한다.
      this.init();
    });
  },
};
</script>

<!-- 샘플 게시판 CRUD 페이지 스타일이다. -->
<style scoped>
/* 제목 링크 커서를 포인터로 보이게 한다. */
a {
  /* 링크 클릭 가능 상태를 표현한다. */
  cursor: pointer;
}
</style>
