Join Snapshot
-
Ready to govern?
+
+ Ready to govern?
+
Get started
diff --git a/apps/ui/src/components/Layout/App.vue b/apps/ui/src/components/Layout/App.vue
index 952f18b93..3010f5992 100644
--- a/apps/ui/src/components/Layout/App.vue
+++ b/apps/ui/src/components/Layout/App.vue
@@ -67,10 +67,6 @@ const hasTopNav = computed(() => {
return 'space-editor' !== String(route.matched[1]?.name);
});
-const bottomPadding = computed(
- () => !['space-proposal-votes'].includes(String(route.name))
-);
-
async function handleTransactionAccept() {
if (
!walletConnectSpaceKey.value ||
@@ -165,7 +161,7 @@ router.afterEach(() => {
:class="{ 'overflow-clip': scrollDisabled }"
>
-
+
-
+
+import dayjs from 'dayjs';
+
+const TIME_FORMAT = 'HH:mm';
+
+const STEPS = {
+ date: { id: 'date', title: 'Select date' },
+ time: { id: 'time', title: 'Select time' }
+};
+
+const props = defineProps<{
+ open: boolean;
+ min?: number;
+ selected: number;
+}>();
+
+const emit = defineEmits<{
+ (e: 'close'): void;
+ (e: 'pick', timestamp: number): void;
+}>();
+
+const { current, isCurrent, goTo, goToNext, goToPrevious, isFirst, isLast } =
+ useStepper(STEPS);
+const date = ref
(props.selected);
+const time = ref(getBaseTime(props.selected));
+const formError = ref(null);
+
+function handleClose() {
+ emit('close');
+}
+
+function handleSubmit() {
+ handleClose();
+ emit('pick', date.value);
+}
+
+function handleDateUpdate(ts: number) {
+ date.value = ts;
+ time.value = getBaseTime(ts);
+ goToNext();
+}
+
+function getBaseTime(ts: number): string {
+ const originalDate = dayjs.unix(props.selected);
+ const selectedDate = dayjs
+ .unix(ts)
+ .set('hour', originalDate.get('hour'))
+ .set('minute', originalDate.get('minute'));
+
+ if (props.min) {
+ const minDate = dayjs.unix(props.min);
+
+ if (selectedDate.isBefore(minDate, 'minute')) {
+ return minDate.format(TIME_FORMAT);
+ }
+ }
+
+ return selectedDate.format(TIME_FORMAT);
+}
+
+function updateDateWithTime() {
+ const [hours, minutes] = time.value.split(':');
+
+ date.value = dayjs
+ .unix(date.value)
+ .set('hour', +hours)
+ .set('minute', +minutes)
+ .startOf('minute')
+ .unix();
+}
+
+function validateForm() {
+ if (!props.min) return;
+
+ const minDate = dayjs.unix(props.min).startOf('minute');
+
+ if (date.value < minDate.unix()) {
+ formError.value = `Time must be equal or greater than ${minDate.format(TIME_FORMAT)}`;
+ return;
+ }
+
+ formError.value = null;
+}
+
+watch([() => current.value.id, time], ([stepId]) => {
+ if (stepId !== 'time') return;
+
+ updateDateWithTime();
+ validateForm();
+});
+
+watch(
+ () => props.open,
+ open => {
+ if (open) {
+ goTo('date');
+ date.value = props.selected;
+ time.value = getBaseTime(props.selected);
+ }
+ }
+);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Previous
+
+
+ Next
+
+
+ Confirm
+
+
+
+
+
diff --git a/apps/ui/src/components/Modal/EditStrategy.vue b/apps/ui/src/components/Modal/EditStrategy.vue
index ff99988a6..b6f2c5f04 100644
--- a/apps/ui/src/components/Modal/EditStrategy.vue
+++ b/apps/ui/src/components/Modal/EditStrategy.vue
@@ -166,7 +166,8 @@ watchEffect(() => {
type: ['string', 'number'],
title: 'Network',
examples: ['Select network'],
- networkId
+ networkId,
+ networksListKind: 'offchain'
}"
/>
{
- const interval = setInterval(() => {
- now.value = parseInt((Date.now() / 1000).toFixed());
- }, 1000);
-
- onUnmounted(() => {
- clearInterval(interval);
- });
-});
+const now = computed(() => Math.floor(timestamp.value / 1000));
function formatTimelineValues(): ProposalTimelineValues {
const data = props.data;
@@ -94,6 +86,12 @@ const states: ComputedRef = computed(() => {
return initial;
});
+
+// Use an offset to compare timestamps to avoid issues when comparing
+// timestamps that are not refreshed synchronously
+function isInThePast(timestamp: number): boolean {
+ return timestamp <= now.value + 1;
+}
@@ -106,12 +104,14 @@ const states: ComputedRef = computed(() => {
>
@@ -122,7 +122,10 @@ const states: ComputedRef
= computed(() => {
class="mb-3 last:mb-0 h-[44px]"
>
- {{ _t(state.value) }}
+