// https://blog.logrocket.com/exploring-advanced-design-patterns-vue-js/
// + MORE ... builder, adapter more usable ...

// BUILDER

// FormBuilder.js
class FormBuilder {
  constructor() {
    this.formFields = [];
  }
  addTextField(name, label, placeholder = '') {
    this.formFields.push({
      type: 'text',
      name,
      label,
      placeholder,
    });
    return this; // Return the builder instance for method chaining
  }
  addNumberField(...) {
    // Add a number field
  }
  addSelectField(...) {
    // Add a select field
  }
  build() {
    return this.formFields;
  }
}
export default FormBuilder;


//  Form.vue 
import FormBuilder from './helpers/FormBuilder';

export default {
  data() {
    return {
      formFields: [],
      formData: {}, // Add a data property to store the form data
    };
  },
  created() {
    /* 
     * Use the FormBuilder class and its methods 
     * to construct the `formFields` object array 
     * with different form fields.
     */
    this.formFields = new FormBuilder()
      .addTextField('name', 'Name')
      .addNumberField(...)
      .addSelectField(...)
      .build();
  },
  methods: {
    handleSubmit() {
      // Log the form data when the form is submitted
      console.log(this.formData);
    },
  },
};



// ADAPTER
// UserAdapter.js
class UserAdapter {
  constructor(externalUserData) {
    this.externalUserData = externalUserData;
  }
  adapt() {
    /*
     * Adapt the external user data to match
     * the component's expected format.
     *
     * Considering the structure of the expected
     * response, grab the right object array
     * (`results`) and its only value.
     *
     * @link https://randomuser.me/api/
     */
    const userData = this.externalUserData.results[0];
    return {
      name: `${userData.name.first} ${userData.name.last}`,
      email: userData.email,
      gender: userData.gender,
      location: `${userData.location.city}, ${userData.location.country}`,
      displayPic: userData.picture.large,
    };
  }
}
export default UserAdapter;

import UserAdapter from './UserAdapter';

export default {
  data() {
    return {
      userAdapter: null,
      user: null
    };
  },
  created() {
    /*
     * Get user data from an external API 
     * with a different format.
     */
    async created() {
      try {
        // Make an API call
        const response = await fetch('...');
        if (!response.ok) {
          throw new Error('Failed to fetch external user data');
        }
        const externalUserData = await response.json();

        /*
         * Create an adapter to convert external weather data 
         * to the format expected by the component.
         */
        this.userAdapter = new UserAdapter(externalUserData);

        // Adapt the data to the component's expected format
        this.user = this.userAdapter.adapt();
      } catch (error) {
        console.error('Error fetching external user data:', error);
        this.errorMessage = 'Failed to load user data. Please try again later.';
      }
    },
  }
};




// Composable pattern
// userPreferences.js
import { ref } from 'vue';

const theme = ref('light');
const language = ref('english');
const notifications = ref(true);

// Getter for theme
const getTheme = () => theme.value;

// Setter for theme
const setTheme = (newTheme) => {
  theme.value = newTheme;
};

// Getter for language
const getLanguage = () => language.value;

// Setter for language
const setLanguage = (newLanguage) => {
  language.value = newLanguage;
};

// Getter for notifications
const getNotificationsEnabled = () => notifications.value;

// Setter for notifications
const setNotificationsEnabled = (enabled) => {
  notifications.value = enabled;
};

export {
  getTheme,
  setTheme,
  getLanguage,
  setLanguage,
  getNotificationsEnabled,
  setNotificationsEnabled,
};


// themeSelector.js
import { computed } from 'vue';
import { getTheme, setTheme } from '../utils/userPreferences';

export function useThemeSelection() {
  const selectedTheme = computed({
    get: () => getTheme(),
    set: (newTheme) => setTheme(newTheme),
  });
  return {
    selectedTheme,
  };
}

// ThemeSelector.vue
<template>
  <div>
    <label for="theme-switch">Theme</label>
    <select id="theme-switch" @change="handleChange" v-model="selectedTheme">
      <option value="light">Light</option>
      <option value="dark">Dark</option>
    </select>
  </div>
</template>
<script>
import { defineComponent } from 'vue';
import { useThemeSelection } from '../composables/themeSelector';

export default defineComponent({
  setup() {
    const { selectedTheme } = useThemeSelection();
    const handleChange = (event) => {
      const newTheme = event.target.value;
      selectedTheme.value = newTheme; // Set the new theme
    };
    return {
      selectedTheme,
      handleChange,
    };
  },
});
</script>


// AnyOther.vue
<template>
  <div class="settings">
    <div class="settings-row">
      <ThemeSelector />
      <div :class="selectedTheme">
        Here's how the {{ selectedTheme }} theme looks like.
      </div>
    </div>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import { useThemeSelection } from './composables/themeSelector';
import ThemeSelector from './components/ThemeSelector';

export default defineComponent({
  setup() {
    const { selectedTheme } = useThemeSelection();

    return {
      selectedTheme,
    };
  },
  components: {
    ThemeSelector
  },
});
</script>

<style>
.light {
  background-color: #fff;
  color: #000;
}
.dark {
  background-color: #000;
  color: #fff;
}
</style>