Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
8.5 kB
1
Indexable
Never
<template>
  <transition name="modal">
  <div :style="`z-index: ${zIndex}`" class="modal-mask">
    <div class="modal-wrapper">
      <template v-if="modalType === 'custom-slot'">
        <div class="modal-container" :style="{ width: width }">
          <div class="modal-header font-16 font-weight-bold" v-if="!noHeader">
            <slot name="header">
              {{ title }}
            </slot>
            <slot name="close">
              <img
                @click="closeModal()"
                class="icon-close icon-close-custom-slot"
                style="cursor: pointer"
                src="/assets/frontend/images/symbols/icon-close.png"
                alt="close"
              />
            </slot>
          </div>

          <div class="modal-body">
            <slot name="body"> default body </slot>
          </div>

          <div class="modal-footer" v-if="!noFooter">
            <slot name="footer">
              <!-- Default Footer -->
              <button @click="handleConfirm()" 
                class="w-100 modal-button-footer" 
                :style="`background-color: ${confirmButtonColor}`"
              >
                {{ buttonTitle }}
              </button>
            </slot>
          </div>
        </div>
      </template>

      <template v-else>
        <div class="modals-wrapper" :style="`width: ${customWidth};`">
          <div class="header" v-if="!noHeader">
            <div @click.prevent="closeModal()" class="close-wrapper">
              <slot name="close">
                <img
                  class="icon-close"
                  src="/assets/frontend/images/symbols/icon-close.png"
                  alt="close"
                />
              </slot>
            </div>
          </div>
          <template v-if="modalType != 'information'">
            <slot name="icon">
              <div
                class="icon-modal d-flex justify-content-center"
              >
                <img
                  v-if="modalType === 'success'"
                  src="/assets/frontend/images/symbols/icon-success.png"
                  alt="success"
                />
                <img 
                  v-else-if="modalType === 'retry'"
                  src="/assets/frontend/images/symbols/icon-warning.png"
                  alt="retry"
                >
                <img
                  v-else-if="modalType === 'failed'"
                  src="/assets/frontend/images/symbols/icon-failed.png"
                  alt="failed"
                >
              </div>
            </slot>
            <slot name="title">
              <div
                class="title d-flex justify-content-center"
              >
                <p>{{ title }}</p>
              </div>
            </slot>
          </template>

          <slot name="description">
            <div
              class="description d-flex justify-content-center"
              :class="modalType === 'information' ? 'font-14 text-btg' : ''"
            >
              <p v-html="description"></p>
            </div>
          </slot>

          <slot name="button">
            <div v-if="modalType != 'information'" class="modal-buttons">
              <button
                v-if="
                  modalType === 'retry' ||
                  modalType === 'failed' ||
                  modalType === 'success'
                "
                @click="handleConfirm()"
                class="w-100 modal-button-warning"
                :style="`background-color: ${confirmButtonColor}`"
              >
                {{ buttonTitle }}
              </button>
              <div
                v-else-if="modalType === 'confirm'"
                class="d-flex justify-content-center"
                style="gap: 20px"
              >
                <button
                  @click="handleCancel()" 
                  class="button-no"
                  :style="`background-color: ${cancelButtonColor}`"
                >
                  {{ cancelButtonTitle }}
                </button>
                <button 
                  @click="handleConfirm()"
                  class="button-yes"
                  :style="`background-color: ${confirmButtonColor}`"
                >
                  {{ confirmButtonTitle }}
                </button>
              </div>
            </div>
          </slot>
        </div>
      </template>
    </div>
  </div>
  </transition>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      default: "",
    },
    description: {
      type: String,
      default: "",
    },
    buttonTitle: {
      type: String,
      default: "Coba Lagi",
    },
    confirmButtonColor: {
      type: String,
      default: "#ff8136"
    },
    cancelButtonColor: {
      type: String,
      default: "rgb(221, 51, 51)"
    },
    modalType: {
      type: String,
      default: "failed",
      required: true
      // retry => Try Again => handleConfirm()
      // failed => OK => handleConfirm()
      // success => OK => handleConfirm()
      // confirm => Yes and No => handleConfirm() dan handleCancel()
      // information => without button => -

      // custom-slot => Modal Custom With Slot => if(noFooter == false) handleConfirm()
      // if (noFooter === true) => without button
    },
    noFooter: {
      type: Boolean,
      default: false,
    },
    noHeader: {
      type: Boolean,
      default: false,
    },
    width: {
      type: String,
      default: "520px",
    },
    customWidth: {
      type: String,
      default: "282px",
    },
    cancelButtonTitle: {
      type: String,
      default: "Batal"
    },
    confirmButtonTitle: {
      type: String,
      default: "Ok"
    },
    zIndex: {
      type: Number,
      default: 1060
    }
  },

  methods: {
    closeModal() {
      this.$emit("close");
    },
    handleConfirm() {
      this.$emit("handleConfirm");
    },
    handleCancel() {
      this.$emit("handleCancel");
    },
  },
};
</script>

<style scoped>
/* Animation */

@keyframes fade-in {
  0% {
    transform: scale(70%) translate(-50%, -50%);
  }
  50% {
    transform: scale(110%) translate(-50%, -50%);
  }
  100% {
    transform: scale(100%) translate(-50%, -50%);
  }
}

@keyframes fade-out {
  0% {
    transform: scale(100%) translate(-50%, -50%);
  }
  50% {
    transform: scale(110%) translate(-50%, -50%);
  }
  100% {
    transform: scale(70%) translate(-50%, -50%);
  }
}

@keyframes bounce {
  0% {
    transform: scale(70%);
  }
  50% {
    transform: scale(110%);
  }
  100% {
    transform: scale(100%);
  }
}

/* Animation */

.modal-container {
  animation: bounce .4s ease-in;
}

.modal-header,
.modal-body,
.modal-footer {
  padding: 20px 40px !important;
}

.modal-body {
  max-height: 600px;
  overflow-y: scroll;
  overflow-x: hidden;
}

.modal-header,
.modal-footer {
  border: none !important;
}

.modal-footer > * {
  margin: 0px;
}

.modals-wrapper {
  position: fixed;
  height: auto;
  background-color: #fff;
  box-shadow: 2px 1px 10px 0px rgba(0, 0, 0, 0.15);
  border-radius: 25px;
  left: 50%;
  top: 50%;
  z-index: 9999;
  transform: translate(-50%, -50%);
  padding: 20px 30px;
  animation: fade-in .2s ease-in;
}

.close-wrapper {
  position: absolute;
  top: -11px;
  right: -11px;
  display: grid;
  place-items: center;
  background-color: #fff;
  border-radius: 50%;
  width: 30px;
  height: 30px;
  box-shadow: 2px 1px 10px 0px rgba(0, 0, 0, 0.25);
  cursor: pointer;
}

.icon-close {
  width: 15px;
  height: 15px;
}

.title p {
  color: #ff7a00;
  font-size: 14px;
  font-weight: 700;
  margin-top: 12px;
}

.icon-modal > img {
  width: 60px;
  height: 60px;
}

.description {
  margin-top: 10px;
  font-size: 12px;
  text-align: center;
  color: #404040;
}

.modal-buttons button {
  margin-top: 20px;
  border: none;
  height: 35px;
  border-radius: 8px;
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}

.modal-button-warning {
  background: #ff8136;
}

.button-yes,
.button-no {
  padding: 0.625em 1.1em;
}

.button-no, .button-yes {
  /* background-color: rgb(221, 51, 51); */
  min-width: 80px;
}


.modal-button-footer {
  /* background: #ff8136; */
  border: none;
  padding: 14px;
  border-radius: 12px;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
}

.icon-close-custom-slot {
  filter: brightness(0) invert(1);
}

@media screen and (max-width: 768px) {
  .modal-body {
    max-height: 80%;
  }
  .modal-header,
  .modal-body,
  .modal-footer {
    padding: 20px 16px !important;
  }
}
</style>